POJ 1276(多重背包)

题目链接:http://poj.org/problem?id=1276

一道很有意思的题目。

做完这道题后发现了很多神奇的东西,原来多重背包问题还可以转化成完全背包问题。

另外,也更多理解了动态规划,稍微明白了一点动归和搜索的差别,还需要继续努力。


别人的解题报告:http://blog.csdn.net/lyy289065406/article/details/6648102


dp[j]记录的是“最接近状态j且<=j”的状态值,即dp[j]<=j

dp的状态是从前向后更新,所以后面的状态会累积前面的状态。

具体解释来说,每个状态都是初始值,然后开始第一次更新,在0~cash-1中如果有一个状态更新,那么由于cash的初始值依然为0,所以cash必然会更新。

在之后的每次更新中,如果不更新dp[cash],那么dp[cash]就会一直保持原来状态。


另外一个就是计数器,感觉也是很神奇的东西。

在二重循环进行之前初始化计数器,也是很难理解的一个地方吧,关键在于cnt[j]=c[j-d[i]]+1;

这里也是一个动态转移方程。


#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=100010;
int cash,N;
int n[15],d[15];
int dp[maxn],cnt[maxn];

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
#endif
    while(~scanf("%d%d",&cash,&N)){
    	for(int i=1;i<=N;i++)
    		scanf("%d%d",&n[i],&d[i]);
    	memset(dp,0,sizeof(dp));
    	for(int i=1;i<=N;i++){
		memset(cnt,0,sizeof(cnt));
    		for(int j=d[i];j<=cash;j++){
    			if(dp[j]<dp[j-d[i]]+d[i]&&cnt[j-d[i]]<n[i]){
    				dp[j]=dp[j-d[i]]+d[i];
    				cnt[j]=cnt[j-d[i]]+1;
    			}
    		}
    	}
    	printf("%d\n",dp[cash]);
    }
	return 0;
}


你可能感兴趣的:(POJ 1276(多重背包))