標籤:
dfs+dp
dfs枚舉每種情況,每層遞迴確定第k個數i:i = a[k-1]+1 to a[k-1]*n+1
當枚舉完一個序列時,使用check()測試它能達到的max
使用dp。設dp[i]為湊成面值為i的最少張數
for(int k=1;a[k]<=i&&k<=t;k++){ if(dp[i-a[k]]<n){ dp[i]=min(dp[i], dp[i-a[k]]+1); }}
注意dp[i]一開始要設成最大值
代碼如下:
#include<iostream>#include<cstring>#define Size 41using namespace std;int a[Size];int dp[10005];int best[Size];int n,t;//n張 t種 int num=0;void save(int x){ num=x; for(int i=1;i<=t;i++){ best[i]=a[i]; }}int check(){ //memset(dp,0x3f,sizeof(dp)); dp[0]=0; int ans=0; bool ok=true; //for(int i=1;i<=t;i++)cout<<a[i]<<" "; //cout<<endl; for(int i=1;ok;i++){ ok=false; dp[i]=0x3f3f3f3f; for(int k=1;a[k]<=i&&k<=t;k++){ if(dp[i-a[k]]<n){ dp[i]=min(dp[i], dp[i-a[k]]+1); ok=true; } } if(ok)ans=i; //cout<<dp[i]<<‘ ‘; } //cout<<endl<<endl; return ans;}void dfs(int k){if(k>t){ int x=check(); if(x>num)save(x); return; } for(int i=a[k-1]+1;i<=n*a[k-1]+1;i++){ a[k]=i; dfs(k+1); }}int main(){ cin>>n>>t; a[1]=1; num=1; dfs(2); for(int i=1;i<=t;i++){ cout<<best[i]<<‘ ‘; } cout<<endl<<"MAX="<<num<<endl; cout<<f; return 0;}
By the way:a[1]一定是1!
PS:你可以看到我把check的第一行memset注釋掉了,因為大部分時候很長的dp數組後面的很多元素都沒有用(max沒有那麼大),所以只需要在迴圈裡用到一個寫一個dp[i]=x03f3f3f3f就可以了。memset使程式變得很慢很慢。(真的很慢啊...)(你真的不需要再試它有多慢了,因為我已經花一個小時幫你試了無數遍了...)
如果想繼續最佳化,可以邊dfs邊維護dp和當前max2的值,這樣dfs迴圈就可以寫成這樣:
i = a[k-1]+1 to max2+1
如果i>max2+1,那麼max2+1這個數將始終無法湊成,結果不會更優
code1047 郵票面值設計