經歷了一週考試周,好久沒寫代碼了。
題目:假設國家發行了n種不同面值的郵票,並且規定每張信封上最多隻允許貼m張郵票。連續郵資問題要求對於給定的n和m的值,給出郵票面值的最佳設計,在1張信封上可貼出從郵資1開始,增量爲1的最大連續郵資區間。例如,當n=5和m=4時,面值爲(1,3,11,15,32)的5種郵票可以貼出郵資的最大連續郵資區間是1到70。
思路:搜索結點的狀態應該是已經確定的郵票面值和它們能夠貼出的最大連續郵資區間,以此來枚舉下一個可能的郵票面值。x[i+1]的取值要和前面i個數各不相同,最小應該是x[i] + 1,最大就是r+1,否則r+1沒有辦法表示。r 表示前i個數最大連續郵資。r可以用遞歸+回溯來求但是時間複雜度比較高,也可以用dp優化一下。
算法作業一直沒動,晚上11點纔開始寫的,然後就r就是直接拿遞歸+回溯寫的,算法思路正確,時間複雜度很高。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int m,n;
int max_r,Sum;
int temp[maxn],ans[maxn];
bool dfs1(int cur,int sum){
if(sum==Sum) return true;
if(cur>m) return false;
for(int i=1;i<=n;i++){
if(dfs1(cur+1,sum+temp[i])) return true;
}
return false;
}
void dfs(int cur){
if(cur>n){
return ;
}
int r;
//求r
for(r=temp[cur]+1;;r++){
Sum=r;
if(!dfs1(1,0)) break;
}
if(r>max_r&&cur==n){
memcpy(ans,temp,sizeof(temp));
max_r=r;
}
for(int i=temp[cur]+1;i<=r;i++){
temp[cur+1]=i;
dfs(cur+1);
temp[cur+1]=0;
}
}
int main()
{
while(cin>>n>>m){
memset(temp,0,sizeof(temp));
temp[1]=1;
max_r=0;
dfs(1);
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
cout<<endl;
cout<<max_r-1<<endl;
}
return 0;
}
比較倉促。。。