1. 程式人生 > >PAT甲級1068【Find More Coins】 dfs

PAT甲級1068【Find More Coins】 dfs

先掛上題目連結~https://www.patest.cn/contests/pat-a-practise/1068

分析:給定多少錢,問能不能通過已有的硬幣組合湊成該整數,如果可以,輸出硬幣字典序最小的組合;否則輸出”No Solution“。此類組合問題我們當然是想到萬能的搜尋~推薦dfs,個人用的比較習慣。注意事項如下:

1、找字典序最小的一種思路是將硬幣按面值大小升序排序,這樣我們dfs搜出的第一種情況便是答案(可以仔細想想為什麼

2、如果就按上面的思路進行深搜會有幾個測試點超時TAT,剪枝則是求出第一種情況後,後續搜尋直接返回(通過設定標誌位判斷)。然而,即使是這樣在最後一個測試點還是會超時,一個原因是資料量比較大,很皮的是這個情況根本沒有solution,於是特判就好啦。求出所有硬幣的面值總和sum,如果sum<m,則直接輸出”No Solution“,於是問題就這樣解決了~

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+10;
int coin[maxn];
int n,m;
bool vis[maxn]={false};
bool flag = false,first=true;
vector<int> ansPath;
int k;
void dfs(int cur, vector<int> path, int w){
	if(flag) return;
	vis[cur] = true;
	if(w > m) return;
	if(w == m){
		flag = true;
		if(first){
			ansPath = path;
			first = false;
		}
		return;
	}
	for(int i = 1; i<=k; i++){
		if(!vis[i]){
			path.push_back(coin[i]);
			dfs(i, path, w+coin[i]);
			vis[i] = false;
			path.pop_back();
		}
	}
}
int main(){
	scanf("%d%d", &n, &m);
	long sum = 0;
	for(int i = 1; i<=n; i++){
		scanf("%d", &coin[i]);
		sum += coin[i];
	}
	if(sum < m) printf("No Solution");
	else {
	
		sort(coin+1, coin+n+1);
		k = n;
		for(int i = 1; i<=n; i++)
			if(coin[i]>=m){
				k = i;
				break;
			}
		dfs(0, ansPath, 0);
		if(flag){
			printf("%d", ansPath[0]);
			for(int i = 1; i<ansPath.size(); i++)
				printf(" %d", ansPath[i]);
		}
		else printf("No Solution");
	}
	
	return 0;
}