P1021 郵票面值設計

P1021 郵票面值設計


0.總結

Get to the points first. The article comes from LawsonAbs!
  • dfs+dp;
  • 注意這種問題dp數組含義的令法很關鍵,我數次將這個dp[i]令成價值i是否可達。而真正的應該設成:到達價值i的最少需要的票數;
  • dfs中的dp數組需要置零,因爲是根據每次的選擇都要重新計算;

1.題意

給出郵票數限制,郵票面值個數限制,請你推算出在合理的限制下信封可達到的最大郵票面值。

2.分析

2.1思路

dfs+dp的題

2.2主要步驟

設dp[i]表示到達i需要最少郵票的數目

分析:
(1)最多能夠貼N張郵票
(2)有k種面值
(3)票值1肯定是必須存在的。
(4)基本數據結構:使用一個數組cho[]用於存儲選擇的票值。用dp[i]表示到達價值i的最小值

針對上面的分析,就可以用dfs深搜窮舉每次dp得到的票值上限—“dp過程中可以到達的最大值”,其下限則是“比當前選擇的數大1的數”。
然後按照上述過程找出最優解即可。

3.代碼

#include<iostream>
using namespace std;
const int N = 10000;
const int INF = 0x3f3f3f;
int n,k;//允許貼的郵票數;面值數 
int cho[N],dp[N];//cho[i]表示需要使用到的數組;dp[i]表示到達i的最小郵票使用數量
int res = 0,cnt = 1;//最後的結果; 已經選了多少個數,初始爲1 
int ans[N];//結果數組
 
void dfs(int low,int up){//下限,上限 
	if(cnt == k){//如果已經選滿了k個 		
		if(res < up-1){
			res = up -1;
			for(int i = 0;i< cnt;i++){//複製整個數組 
				ans[i] = cho[i];
			}	
		}
		
		return ;
	} 
	for(int i = low+1; i<=up;i++){
		cho[cnt] = i;
		cnt++;
		
		//dp計算值 
		fill(dp,dp+N,INF);//重置 
		dp[0] = 0;
		for(int l = 0;l < cnt;l++){//放前l個郵票 
			for(int j = cho[l] ; j <= n*cho[cnt-1]; j++){//	
				if(dp[j-cho[l]] != INF){//如果l-cho[j]可達 
					dp[j] = min(dp[j],dp[j-cho[l]]+1);	
				}				
			} 
		} 
		int temp;
		//找出dp到達的最大值
		for(int j = 0;j<=n*cho[cnt-1]+1;j++){
			if(dp[j] > n){
				temp = j; 
				break;//找出上限值 
			}				
		} 
		dfs(i+1,temp);
		cnt--;//清零		 
	}
}
 
int main(){
	cin >> n >> k;
	//初始化
	cho[0] = 1; 
	fill(dp,dp+N,INF); 
	dp[0] = 0;
	dfs(1,n+1);//[1,n] 
	for(int i = 0;i< k;i++){
		cout << ans[i]<<" ";
	} 
	cout <<"\nMAX="<< res <<"\n";	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章