简单背包问题

出自算法引论-一种创造性方法

1、背包问题:

给定一个整数K和N个大小不同的物品,第i个物品的体积为S[i],寻找一个子集使子集的和大小等于K,或者确定不存在这样的子集


解答:

动态规划,即建立P[n][k](0<=n<=N,0<=k<=K)大小二维数组保存解,根据前面的解P[n-1][k],P[n-1][K-S[n]]的状态来确定。


代码:


const int N = 6;//物品数量

int S[N+1] = {0,3,5,6,8,2,4};//物品体积,S[0]无效

const int K = 14;//背包大小


typedef struct _state{

    int exist;//是否存在解

    int belong;//是否包含当前S[n]

}state;

state P[N+1][K+1];


int knapsack()

{

    P[0][0].exist = 1;

    std::cout<<"  0 ";

    for (int k = 1; k <= K; k++){

        P[0][k].exist = 0;

        std::cout<<k<<" ";

    }

    std::cout<<std::endl;

    

    for (int i = 1; i <= N; i++){

        std::cout<<S[i]<<" ";

        for (int k =0; k <= K;k++){

            P[i][k].exist = 0;

            if (P[i-1][k].exist){

                P[i][k].exist = 1;

                P[i][k].belong = 0;

            }

            else if (k-S[i]>=0){

                if (P[i-1][k-S[i]].exist){

                    P[i][k].exist = 1;

                    P[i][k].belong = 1;

                }

            }

            

            if (P[i][k].belong && P[i][k].exist) std::cout<<"I ";

            else if(P[i][k].exist) std::cout<<"O ";

            else std::cout<<"- ";

            if (k>=10)

                std::cout<<" ";

            

        }

        std::cout<<std::endl;

    }

    return P[N][K].exist;

}

2、习题

问题:令x1,x2,。。。xn是一组整数,试找到一个划分这个数组为2部分相等的方法,或者不能做出这样的划分

解答:与背包一样的解法,只是此时背包K的值为(x1+x2+...+xn)/2

代码:

int knapsack_for_sum_mod_2()

{

    P[0][0].exist = 1;

    std::cout<<"  0 ";

    for (int k = 1; k <= K; k++){

        P[0][k].exist = 0;

        std::cout<<k<<" ";

    }

    std::cout<<std::endl;

    

    for (int i = 1; i <= N; i++){

        std::cout<<S[i]<<" ";

        for (int k =0; k <= K;k++){

            P[i][k].exist = 0;

            if (P[i-1][k].exist){

                P[i][k].exist = 1;

                P[i][k].belong = 0;

            }

            else if (k-S[i]>=0){

                if (P[i-1][k-S[i]].exist){

                    P[i][k].exist = 1;

                    P[i][k].belong = 1;

                }

            }

            

            if (P[i][k].belong && P[i][k].exist) std::cout<<"I ";

            else if(P[i][k].exist) std::cout<<"O ";

            else std::cout<<"- ";

            if (k>=10)

                std::cout<<" ";

            

        }

        std::cout<<std::endl;

    }

    

    //打印解

    int n = N;

    int k = K;

    while(n>=1 && k>=0){

        if (P[n][k].exist){

            if (P[n][k].belong){

                std::cout<<S[N]<<" ";

            }

            else{

                for (; n >=1; n--){

                    if (P[n][k].belong){

                        std::cout<<S[n]<<" ";

                        k-=S[n];

                        break;

                    }

                }

            }

        }

        else

            break;

    }

    std::cout<<std::endl;

    

    return P[N][K].exist;

}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值