题目大意:
每个糖果的价值都是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");
}