| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5229 人关注过本帖
标题:回溯法求解子集和数问题
只看楼主 加入收藏
sunjinlong
Rank: 1
等 级:新手上路
帖 子:19
专家分:0
注 册:2008-11-19
结帖率:100%
收藏
 问题点数:0 回复次数:4 
回溯法求解子集和数问题
    给定一个n个整数的集合X={x1,x2....xn}和整数y,找出和等于y的X的子集Y.比如:若X={10,20,30,40,50,60}和y=60,则有三种不同长度的解,它们分别是{10,20,30},{20,40},{60}.这个问题可以用另一种方法明确表达,使得解是一种明显的长度为n的布尔向量,于是上面的三个解可以用布尔向量表示为:
{1,1,1,0,0,0},{0,1,0,1,0,0},{0,0,0,0,0,1}。
    今天试图用c语言实现该算法,但是总也调不出来。请大虾帮忙!我的程序代码如下:


#include <stdio.h>

int isLegal(int a[],int c[],int n,int y){
     int i;
     int sum=0;
     for(i=0;i<n;i++){
          if(c[i]==1){
                sum=sum+a[i];
          }
     }

     if(sum==y){
        return 1;
     }else{
        return 0;
     }
}

int isPart(int a[],int c[],int n,int y){
     int i;
     int sum=0;
     for(i=0;i<n;i++){
          if(c[i]==1){
                sum=sum+a[i];
          }
     }

     if(sum<y){
        return 1;
     }else{
        return 0;
     }
}

int partition(int A[],int c[],int n,int y){
    int k,j;
    int flag=0;
    for(k=0;k<n;k++){
        c[k]=-1;
    }

    k=0;
    while(k>=0){
        while(c[k]<=0){
            c[k]=c[k]+1;
            if(isLegal(A,c,n,y)){
                flag=1;
                /*储存或输出解向量*/
                printf("\n");
                for(j=0;j<n;j++){
                    printf("%d  ",c[j]);
                }
                break;

            }
            else if(isPart(A,c,n,y)){
                k=k+1;
                printf("aaaaa\n");
            }
        }

        c[k]=-1;
        k=k-1;
    }
    return flag;
}

void main(){
    int A[6]={10,20,30,40,50,60};
    int flag=0;
    int c[6]={-1,-1,-1,-1,-1,-1};
    flag=partition(A,c,6,60);
    if(flag){
        printf("find the answer!");
    }
    else{
        printf("can not find the answer!");
    }

    getch();
}
搜索更多相关主题的帖子: 回溯 子集 求解 
2010-03-22 22:01
okgays
Rank: 2
等 级:论坛游民
帖 子:15
专家分:26
注 册:2010-3-23
收藏
得分:0 
你的程序逻辑上有错误,导致运行时会出现段错误,在程序中c[i]值永远不可能为1,只能到0;故程序一直不能跳出循环,输出aaaaaaa,导致溢出错误。
我自己写了一个,你可以参考一下:
#include <stdio.h>

//定义一个结点
struct node{
    int data;        //存放集合中的元素
    int flag;        //标记集合中的元素,若为1,表示该元素在目标集合中,若为0,表示不在其中
};               

/****从集合的num个元素中查找满足以下要求的元素,并输出。要求如下:
*****被选中的元素之和为指定值y     
*****/
void search(struct node *pnode, int num, int y)
{
    int tmp = y;        //y的值在下面会发生改变,故先记下初始值,当再次扫描元素时保证y值不变
    int count = 0;     //判断是否有满足要求的集合,若有则大于0,否则等于0

    for (int k = num - 1; k >= 0; --k) //从最后一个节点的元素值开始扫描
    {
        if (pnode[k].data <= y)   //若元素值小于等于y则记下此元素,并将y值减去此元素的值
        {
            int t = k;

            while ( t >= 0 && y >0 )
            {
                if ( pnode[t].data <= y )
                {
                    y = y - pnode[t].data;
                    pnode[t].flag = 1;
                }

                --t;
            }

            if (y == 0)        //当y为0时表示满足要求的元素已找到,输出这些被标记的节点的元素值
            {
                ++count;

                printf("the target set is : {  ");
                for (int i = 0; i < num; ++i)
                {
                    if (pnode[i].flag == 1)
                    {
                        printf("%d  ", pnode[i].data);
                    }
                }

                printf("}\n");
            }

            for (int i = 0; i < num; ++i) //重新初始化各个元素的标记状态为0,一边下次扫描
                pnode[i].flag = 0;

            y = tmp;
        }
    }
    if (!count)
        printf("the target set is not existed\n");
}

int main()
{
    int n = 6;            //集合中元素的个数
    int tar = 60;
    struct node Anode[6];  //由集合中的每个元素和相应的标记组成的结点数组
   
    for (int i = n - 1; i >= 0; --i)
    {         
        Anode[i].flag = 0;
        Anode[i].data = 10 * (i + 1);
    }         //初始化结点中元素的标记为未标记状态,并给集合中元素赋值

    search(Anode, n, tar);

    return 0;
}
2010-03-23 19:13
sunjinlong
Rank: 1
等 级:新手上路
帖 子:19
专家分:0
注 册:2008-11-19
收藏
得分:0 
自己写的程序,谢谢你的帮忙
#include <stdio.h>
/*回溯法求解子集和数问题*/
int isLegal(int a[],int c[],int n,int y,int k){
     int i;
     int sum=0;
     for(i=0;i<n;i++){
          if(c[i]==1){
                sum=sum+a[i];
          }
     }

     if((sum==y)&&(k<=n-1)){
        return 1;
     }else{
        return 0;
     }
}

int isPart(int a[],int c[],int n,int y,int k){
     int i;
     int sum=0;
     for(i=0;i<n;i++){
          if(c[i]==1){
                sum=sum+a[i];
          }
     }

     if((sum<y)&&(k<n-1)){
        return 1;
     }else{
        return 0;
     }
}

int partition(int A[],int c[],int n,int y){
    /*回溯迭代算法*/
    int k,j;
    int flag=0;
    for(k=0;k<n;k++){
        c[k]=-1;
    }

    k=0;
    while(k>=0){
        while(c[k]<=0){
            c[k]=c[k]+1;
            if(isLegal(A,c,n,y,k)){
                flag=1;
                /*储存或输出解向量*/
                printf("\n");
                for(j=0;j<n;j++){
                    if(c[j]<0){c[j]++;}
                    printf("%d  ",c[j]);

                }


            }
            else if(isPart(A,c,n,y,k)){
                k=k+1;

            }
        }

        c[k]=-1;
        k=k-1;
    }
    return flag;
}

void main(){
    int A[6]={10,20,30,40,50,60};
    int flag=0;
    int c[6]={-1,-1,-1,-1,-1,-1};
    flag=partition(A,c,6,60);
    if(flag){
        printf("find the answer!");
    }
    else{
        printf("can not find the answer!");
    }

    getch();
}
2010-04-04 19:13
hey2000
Rank: 1
来 自:武汉
等 级:新手上路
帖 子:5
专家分:2
注 册:2010-4-4
收藏
得分:0 
几位的算法还是没看明白……

Read the fucking source code !
2010-06-19 14:55
喝杯Java
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2017-2-24
收藏
得分:0 
回复 2楼 okgays
有个问题,就是如果你y = y - pnode[t].data;中y小于0后,你没有程序去弄,就算不出来

2017-02-24 14:58
快速回复:回溯法求解子集和数问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017679 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved