UVA - 10163 Storage Keepers

開始並沒有注意到需要使兩個量最優與只要求一個量最優有什麼不同,就定義dp[i][j]爲前i個人看守j個storage的最大安全線,然後順便把wage求出來。交上去卻一直wa。疑惑不解的去看別人的代碼,鬱悶的發現所有人都用了兩次dp,我開始非常不解,既然薪水是由人決定的爲什麼還要再用一次dp?後來仔細想想才發現這樣做的道理,從較高的抽象層面看,定義的狀態dp[i][j]本身就是求一個量的最優值的,而不是兩個量。從代碼具體實現看,對於薪水,由於遍歷i的時候,i小的總是在i大的之前訪問,就有可能導致較小的i添加進去能夠導致安全線的最優解但不是薪水最優解,且添加進去之後無法移除,導致之後的狀態無法達到最優解。也就是安全線是一樣的,但薪水是可能達不到最優解得。所以,對於兩個量,必須用兩個dp。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAXN 105
#define MAXM 35
#define INF 200000
using namespace std;

int s[MAXM],n,m,dp[MAXM][MAXN],wage[MAXM][MAXN];

void init(){
	memset(wage,0,sizeof(wage));
	memset(dp,0,sizeof(dp));
	for(int i=0;i<=m;i++)
		dp[i][0]=INF;
}

int main(){
	while(~scanf("%d %d",&n,&m)&&n+m){
		for(int i=1;i<=m;i++){
			scanf("%d",&s[i]);
		}
		sort(s+1,s+m+1);
		init();
		for(int i=1;i<=m;i++){
			for(int j=0;j<=n;j++){
				for(int t=1;t<=j;t++){
					if(dp[i-1][j-t]>0&&s[i]/t>0){
						if(min(dp[i-1][j-t],s[i]/t)>dp[i][j]){
							dp[i][j]=min(dp[i-1][j-t],s[i]/t);
							wage[i][j]=wage[i-1][j-t]+s[i];
						}
						else if(min(dp[i-1][j-t],s[i]/t)==dp[i][j]){
							wage[i][j]=min(wage[i][j],wage[i-1][j-t]+s[i]);
						}
					}
				}
				if(j!=0&&dp[i-1][j]>dp[i][j]){
					dp[i][j]=dp[i-1][j];
					wage[i][j]=wage[i-1][j];
				}
				else if(j!=0&&dp[i-1][j]==dp[i][j]&&dp[i][j]!=0)
					wage[i][j]=min(wage[i][j],wage[i-1][j]);
			}
		}
		int safe=dp[m][n];
		if(safe==0){
			cout<<"0 0"<<endl;
			continue;
		}
		memset(dp,0x7f,sizeof(dp));
		dp[0][0]=0;
		for(int i=1;i<=m;i++){
			for(int j=0;j<=n;j++){
				for(int t=1;s[i]/t>=safe&&t<=j;t++){
					dp[i][j]=min(dp[i][j],dp[i-1][j-t]+s[i]);
				}
				dp[i][j]=min(dp[i][j],dp[i-1][j]);
			}
		}
		cout<<safe<<' '<<dp[m][n]<<endl;
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章