POJ 1276 Time Machine【多重背包】

来源:互联网 发布:php mysqli connect 编辑:程序博客网 时间:2024/06/13 05:45

这个多重背包问题我单纯地把它转化成了0-1背包问题,然后列出状态转移方程 dp[i][j] = max{ dp[ i-1][ j - k * V[i]] + k , dp[ i-1][ j-1] }

这样看起来是需要三重循环哦。。开心的列了出来【图样图森破,简直拿衣服】

DP部分的代码写成了这样

for( i = 1; i <= n; i++){for( j = N; j >= bill[i].mon; j--){temp = 0;for( k = 1; k <= bill[i].fre; k++){if( j-k*bill[i].mon < 0) break;if( dp[j] < dp[j-k*bill[i].mon] + k)dp[j] = dp[j-k*bill[i].mon] + k;}}}
之后我猛然发现一个问题,对于给出的数据中取不到的值也会计算成使 dp[j] 最大的那个 j 值....比如对于输入数据 633 4  500 30  6 100  1 5  0 1 。应得数据应该为630,但是实际给出的还是633。。。

 我改了以后发现原来就算是630之前也会连续取一样的值。。。

那么如果记录最大值呢?然后我写成了这样。。。

for( i = 1; i <= n; i++){for( j = N; j >= bill[i].mon; j--){temp = 0;for( k = 1; k <= bill[i].fre; k++){if( j-k*bill[i].mon < 0) break;if( dp[j] < dp[j-k*bill[i].mon] + k)dp[j] = dp[j-k*bill[i].mon] + k;temp =  k*bill[i].mon;}if( temp > max) max = temp;}}
记录最大值这个思路是对的,但是我写错了,这个程序明显是求至票面额倍数的最大值。。。这里有点想当然了,没有进一步思考,下次要吸取教训

不过既然记录了最大值,而且也不需要求最大的张数,我们也就不需要记忆每一个钱数的张数了。那么只需要一个数组来记录某值是否被访问到就可以了。于是我就看懂了网上一部分人的题解23333333.。。。参考了别人的题解,我终于做出来了

下面放上AC题解之一【用dp来存储是否被访问到】

#include<stdio.h>#include<string.h>struct A{int mon;int fre;}bill[15];int main(void){int N, n, i, j, k, temp, max; int dp[100005];while( scanf("%d", &N) != EOF){memset( dp, 0, sizeof(dp));scanf("%d", &n);for( i = 1; i <= n; i++){scanf("%d%d", &bill[i].fre, &bill[i].mon);}if( n == 0 || N == 0){printf("0\n"); continue;}max = 0;dp[0] = 1;for( i = 1; i <= n; i++){                                  // 对每一个bill进行遍历,之前我还弄反了for( j = max; j >= 0; j--){if( dp[j])for( k = 1; k <= bill[i].fre; k++){temp = j + k*bill[i].mon;  // 能够取到的值if( temp > N)continue;dp[temp] = 1;              // 记录,已经访问if( temp > max) max = temp;// 取最大值}}}printf("%d\n", max);}return 0;}
事实上我之前是被之前自己写的转移方程固化了思维,没有想到这道题还可以这样想。

之前的状态转移方程应该是对的。。。。张数什么的都是能算出来的。。。要是换一个问法也许我就能AC了。。。。嘤嘤嘤(并不能,因为我还落后地使用着二维数组。。所以可能会超时T0T)

0 0
原创粉丝点击