1014 题目大意:
两个娃子分弹珠,有六种可能(1-6)的好坏程度的弹珠,给定每种好坏弹珠的数量,求是否存在使好坏度总和均分的分配方案。
1026 题目大意:
一台出纳机,根据不同的金额请求“尽量”吐出更多的金额代券,最高等值。问给定一个金额数量,和机器内不同面额代券的存,
量,问机器能吐出逼近请求的最高面值总和是多少。
题目模型很明显,很容易联系到多重背包。对于第一题,首先将弹珠价值总和减半表示为v,然后构造一个v容量背包,题目等价于询问
该背包的最大存入方案是否能使存入总重量恰好等于v?转移方程: dp[i][v]=Max( dp[i-1][v], dp[i-1][v-k*w[j]]+k*c[i] | w[i] = c[i], 0<=k<=maxK )。
同理第二题的转移方程与1014基本一样,物品收益即为物重,dp结果即为v容背包最大置入量。
题目数据很弱,据说硬搜能过。。。 不过还是按照多重背包的优化技巧来做,即用二进制拆分物品数,容易证明这样的拆分能保证最优性
和正确性。时间复杂度O(C*V*logN)。 对于O(C*V)算法,可以参考 《国家集训队2009论文集浅谈几类背包题 》中单调队列优化DP的技巧。
1014:
1
#include<cstdio>
2
#include<cstdlib>
3
#include<cstring>
4
#define max(a,b) (a>b)?a:b;
5
#define MAXV 20000*6+1
6
int dp[MAXV];
7
int nk[6];
8
9
int main()
{
10
int i,k,min,v;
11
int cnt,sum;
12
int _case=0;
13
while(1)
{
14
for(sum=i=0;i<6;i++)
{
15
scanf("%d",&nk[i]);
16
sum+=nk[i]*(i+1);
17
}
18
if( !nk[0] & !nk[1] & !nk[2] & !nk[3] & !nk[4] & !nk[5] ) break;
19
_case++;
20
if( _case!=1 ) printf("\n");
21
if( sum%2 )
{
22
printf("Collection #%d:\n",_case);
23
printf("Can't be divided.\n");
24
}
25
else
{
26
sum/=2;
27
memset(dp,0,sizeof(int)*(sum+1));
28
for(i=0;i<6;i++)
{
29
cnt=1;
30
k=(sum/(i+1)>=nk[i])?nk[i]:sum/(i+1);
31
while(k)
{
32
if( cnt>k ) cnt=k;
33
k-=cnt;
34
min=cnt*(i+1);
35
for(v=sum;v>=min;v--)
36
/**//* 对每一个拆分数 cnt,单独做 0/1背包 */
37
dp[v]=max(dp[v],dp[v-cnt*(i+1)]+cnt*(i+1));
38
cnt<<=1;
39
}
40
}
41
if( sum == p[sum] )
{
42
printf("Collection #%d:\n",_case);
43
printf("Can be divided.\n");
44
}
45
else
{
46
printf("Collection #%d:\n",_case);
47
printf("Can't be divided.\n");
48
}
49
}
50
}
51
return 0;
52
}
53