C 使用最少数量的数组查找覆盖所有元素的数组组合

C 使用最少数量的数组查找覆盖所有元素的数组组合,c,arrays,algorithm,C,Arrays,Algorithm,你好,我是C语言新手,一直在尝试解决各种问题。我最近一次尝试解决的问题已经解决了一半,最后一步我需要知道的是这一点。如果存在类似的各种阵列: int A[4] = {1,0,1,0}; int B[4] = {1,0,0,1}; int C[4] = {0,1,1,0}; int D[4] = {0,1,0,1}; 所有数组的长度都是相同的“L”。我需要找出使用最少数组数量的组合,当组合时(相同位置的所有元素被添加到一个长度相等的数组中,该数组最初用零填充),将导致一个长度为“L”的数组,其中

你好,我是C语言新手,一直在尝试解决各种问题。我最近一次尝试解决的问题已经解决了一半,最后一步我需要知道的是这一点。如果存在类似的各种阵列:

int A[4] = {1,0,1,0};
int B[4] = {1,0,0,1};
int C[4] = {0,1,1,0};
int D[4] = {0,1,0,1};
所有数组的长度都是相同的“L”。我需要找出使用最少数组数量的组合,当组合时(相同位置的所有元素被添加到一个长度相等的数组中,该数组最初用零填充),将导致一个长度为“L”的数组,其中没有一个0

对于上面的示例,它将是A&D或B&C,因此答案将是两个数组

它不必用1来填充,可以是2或3或其他。只需要不剩下零。由于我们只搜索最小数量,可能有多个组合,但只有一个答案。我会小于10。但阵列的数量将从1到500不等


我曾尝试使用在线学习的图形算法,但这个问题一直困扰着我。

我已使用分而治之方法解决了这个问题。
逻辑
首先,考虑数组的集合<代码>数据< /代码>,我们从中找到最小的数组组,其中组合的数组只有1个。 简单地说,我们可以从集合中一个接一个地获取所有数组,并从剩余数组中找到最小的组,这样组中的数组和当前数组的组合就满足了条件最小的组合(数组组+当前数组)是我们的解决方案。

我们可以简单地给出问题的递归定义。

解决方案

#include<stdio.h>
#define L 4 //length of the array
#define N 4 //number of arrays
int best[N]; //array to keep track of best combination.
int nbest=N; //number of best arrays in best combination.
int D[N][L]={{1,0,1,0},{1,0,0,1},{0,1,1,0},{0,1,0,1}}; //data
int func(int track[],int ar[],int d); //get best combination
int * copy(int *a,int len); //copy contant of a to b.
int * combine(int a[],int b[],int len);
int main()
{
    int i,j;
    int empty[L]={0,0,0,0};//initial combination
    int init[N]={-1,-1,-1,-1};//initial track.
    // initialize 'best' array.
    for(i=0;i<N;i++)
        best[i]=-1;
    // initial function call
    func(init,empty,0);
    // print the result.
    printf("best combination..\n");
    for(i=0;i<nbest;i++){
        for(j=0;j<L;j++)
            printf("%d, ",D[best[i]][j]);
        printf("\n");
    }
    return 0;
}

/*
    * this is recursive function work on data array 'D'.
    * array 'track' is used to keep track of the arrays of current combination.
    * array 'ar' is indicate the current combination.
    * int 'd' indicate the number of arrays in current combination.
*/
int func(int track[],int ar[],int d){
    int i,j,*t,*tr;
    if(d>=N) //check if there are arrays remain to combine.
        return 0;   
    if(check(ar,L)){ //check if the combination is valid.
        if(nbest>d){ //check if the current solution is better then the best.
            nbest=d;
            for(i=0;i<d;i++)
                best[i]=track[i];
        }
        return 1;
    }
    tr=copy(track,N); //make local copy of track.
    for(i=0;i<N;i++){ // make combination with all remaining arrays.
        if(isin(tr,i)) // check if current array is already in combination.
            continue;
        t=copy(ar,L); //make local copy of current combination.
        tr[d]=i; // update track array to track current array.
        t=combine(t,D[i],L); // combine the array with current combination.
        if(func(tr,t,d+1)){ // recursive call, brake the loop if the current combination is valid.
            break;
        }
    }
    return 0;
}

int * combine(int a[],int b[],int len){ // return combination of array 'a' & 'b'.
    int *c=(int *)calloc(len,sizeof(int));
    int i;
    for(i=0;i<len;i++){
        c[i]=a[i]||b[i];
    }
    return c;
}

int * copy(int *a,int len){ // this function return copy of array 'a' of length 'len'
    int i;
    int *t=(int *)calloc(len,sizeof(int));
    for(i=0;i<len;i++)
        t[i]=a[i];
    return t;
}

int check(int a[],int len){ // check if the array is valid combination. i.e. all elememnts are 1.
    int i;
    for(i=0;i<len;i++)
        if(a[i]!=1)
            return 0;
    return 1;
}

int isin(int *ar,int index){ // return 1 if int 'index' is exist in array 'ar'.
    int i;
    for(i=0;i<N;i++)
        if(ar[i]==index)
            return 1;
    return 0;
}
#包括
#定义数组的L 4//长度
#定义N 4//数组的数量
最佳整数[N]//数组以跟踪最佳组合。
int-nbest=N//最佳组合中的最佳阵列数。
int D[N][L]={1,0,1,0},{1,0,0,1},{0,1,1,0},{0,1,0,1}//数据
int func(int track[],int ar[],int d)//获得最佳组合
int*副本(int*a,int len)//将a的内容复制到b。
整数*合并(整数a[],整数b[],整数len);
int main()
{
int i,j;
int empty[L]={0,0,0,0};//初始组合
int init[N]={-1,-1,-1};//初始轨迹。
//初始化“最佳”数组。

对于(i=0;i1)按1的总数将剩余的排序到你需要的位置。2)取最高的排序。3)重复我很抱歉,但我不明白。剩余的是什么?未填充的零?约翰提出了一个贪婪算法,但它不一定给出最佳结果。例如:{1,0,1,1,0},{1,1,0,0},{0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 1}]。最好的解决方案是只取第一个数组,但贪婪算法会从第一个数组开始,因为它有3个数组,然后还要添加其他数组。@maraca这是真的。听起来我明白了。谢谢。我会通过理解和使用您的代码来尝试改进。谢谢。您可以去掉数组上的所有循环。1.打开一组数组组合成一组具有
l
位的无符号整数。2.组合两个整数只是a | b(不再循环位位置)3.您希望通过对最小所需子集进行ORing来实现的目标数为2^l-1。
l
位设置为1.Btw。我认为这是回溯,而不是分治。也许可以进行一些优化(提前返回,首先查看有希望的分支),但总的来说,这似乎是一条路要走,因为这个问题是NP完全问题。@maraca我也这么认为。但正如你所看到的,数组的长度可能很大,在这种情况下,我们必须使用多个长变量。所以​ 在这种情况下,整数或long是困难的&我们还需要为数组到整数的转换编写代码。@maraca它看起来像是回溯。因为这是NP完全类型的问题。&我试图在代码中看不到最佳结果时通过返回来进行优化。我们也可以先考虑有前途的分支。我认为在这种情况下,我们必须使用A.I.算法,如启发式搜索。