# Dynamic Programming# DFS# Greedy# Backtracking

f433 - 165 - Stamps

🔗 前往 ZeroJudge 原題

題目描述

題目要求找出 K 種面額的郵票,使得使用最多 H 張郵票可以連續表示從 1 開始的最大值。輸出這些面額以及最大可表示的值。

解題思路

此題使用深度優先搜尋 (DFS) 搭配動態規劃 (DP) 來解決。首先,使用 DFS 枚舉所有可能的 K 個郵票面額組合。對於每種組合,使用 DP 計算可以表示的最大連續值。DP 陣列 dp[i] 表示是否能用給定的郵票面額表示數值 i。DP 的過程類似背包問題,嘗試用不同的郵票面額來更新 dp 陣列。在 DFS 過程中,記錄能表示的最大連續值,並在所有組合中找到最佳解。如果無法用給定的郵票面額表示從 1 到某個值的連續數列,則記錄下目前無法表示的最小值,並以此作為終止條件。

複雜度分析

  • 時間複雜度: O(33^k * 101)。其中 k 是郵票種類數,33 是郵票面額的最大值,101 是 DP 陣列的大小。DFS 枚舉郵票面額組合的複雜度是 O(33^k),DP 計算最大連續值的複雜度是 O(101)。
  • 空間複雜度: O(101 + k)。DP 陣列 dp 的大小是 O(101),ansp 陣列儲存最佳郵票面額組合,大小是 O(k)。

程式碼

#include <iostream>
using namespace std;
int h,k,dp[121],ansp[11],mc[11],ans;
void dfs(){
	for(int i=0;i<101;++i){
		dp[i]=0;
	}
	for(int i=0;i<101;++i){
		if(i==0||dp[i]){
			if(dp[i]<h){
				for(int j=0;j<k;++j){
					int nv=i+mc[j];
					if(dp[nv]==0){
						dp[nv]=dp[i]+1;
					}
					else{
						dp[nv]=min(dp[i]+1,dp[nv]);
					}
				}
			}
		}
		else if(dp[i]==0){
			if(i-1>ans){
				ans=i-1;
				for(int j=0;j<k;++j){
					ansp[j]=mc[j];
				}
			}
			break;
		}
	}
	return;
}

void fc(int c,int it){
	if(it==k){
		dfs();
		return;
	}
	for(int i=c+1;i<33;++i){
		mc[it]=i+1;
		fc(i,it+1);
	}
}

int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	while(cin >> h >> k){
		if(h==0&&k==0)break;
		ans=0;
		mc[0]=1;
		fc(0,1);
		for(int i=0;i<k;++i){
			cout << ansp[i] << " ";
		}
		cout << "-> " << ans << "\n";
	}
}

Discussion