poj_1014

题目大意:

每个糖果的价值都是1,2,3,4,5,6 这六种之一。现在有一堆糖,需要判别是否能够把糖果分成两堆,两堆的价值相同。


分析:

        为了接下来叙述顺畅,我把题目做以下等价变换:

每个糖果的重量都是1,2,3,4,5,6 这六种之一。现在有一堆糖,需要判别是否能够把糖果分成两堆,两堆重量相同。

        可以先算出糖果总价值W

        如果W是奇数,直接判断不行。

        如果W是偶数,问题转化为:判断能不能选出一些糖果,刚好装满容量为W/2的背包。这样,问题就转化为了变种的完全背包问题。


完全背包问题:

给定N种物品和一个背包,第i个物品的价值为vi,重量为wi,每个物品可以选择放0个,1...n个到背包中,背包承重为c,求使得背包中物品价值最大的放法。

解法:由于完全背包问题也满足最优子结构,并且有重复子结构,所以使用动态规划的方法

定义状态:c[i][m]表示考虑第i件物品( 1<=i<=n )时,背包容量(这里的容量就是指总容量,可以把背包想成由很多小背包组成)为m的状态下,可以获得的最大价值。

C[i][m] = max{ c[ i-1 ][ m-k*wi ] + k*vi  |  0<=k*wi<=c } 

C[0][m] = 0

只能装满条件下,C[0][0]=0, C[0][i]( 1<=i<=c )初始化为 -∞,这样就使得当前背包没有装满的策略价值都是-∞


我们把等价变换后的题目中每种糖果的价值 都设为1,这样就可以套用完全背包问题了。


源代码:

#include <stdio.h>
#include <stdlib.h>
int judge( int w[6] ){
    int weight[2][6],type,max;
    int cache[100][100]={0};
    int i,j,k,c;//c总容量 
    for( i=1,j=0,c=0; i<=6; ++i ){
        c = c+i*w[i-1];
        if( w[i-1] ){
            weight[0][j] = w[i-1];//数量 
            weight[1][j] = i;//质量 
            ++j;
        }
    }
    type = j;

    if(c%2){
        return 0;//不行 
    } else{
        c = c/2;
        for( j=1;j<=99;++j )
            cache[0][j] = -10000000;//完全背包问题,为了保证装满的初始化方式 
        for( i=1; i<=type; ++i ){//动态规划填表 
            for( j=0; j<=c; ++j ){
                max = -10000000;
                for( k=0; k<=weight[0][i-1] && k<=j/weight[1][i-1]; ++k ){
                    if( max<cache[i-1][j-k*weight[1][i-1]]+k )
                        max = cache[i-1][j-k*weight[1][i-1]]+k; 
                }
                cache[i][j] = max;
            }
        } 
    } 
    if(cache[type][c]>0){
        return 1;
    } else{
        return 0;
    }
}
int main(){
    int value[10][6],i;
    scanf("%d %d %d %d %d %d",&value[0][0],&value[0][1],&value[0][2],&value[0][3],&value[0][4],&value[0][5]);
    for( i=0; value[i][0]!=0||value[i][1]!=0||value[i][2]!=0||value[i][3]!=0||value[i][4]!=0||value[i][5]!=0; ){
        ++i;
        scanf("%d %d %d %d %d %d",&value[i][0],&value[i][1],&value[i][2],&value[i][3],&value[i][4],&value[i][5]);
    }
    for( i=0; value[i][0]!=0||value[i][1]!=0||value[i][2]!=0||value[i][3]!=0||value[i][4]!=0||value[i][5]!=0; ++i ){
        if(judge(value[i])==1){
            printf("ok\n");
        } else{
            printf("fail\n");
        }
    }
    system("pause");
} 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值