問題 1576: [藍橋杯][算法提高VIP]郵票面值設計
時間限制: 1Sec 內存限制: 128MB 提交: 103 解決: 48
題目描述
給定一個信封,最多隻允許粘貼N張郵票,計算在給定K(N+K≤13)種郵票的情況下(假定所有的郵票數量都足夠),如何設計郵票的面值,能得到最大值MAX,使在1~MAX之間的每一個郵資值都能得到。
例如,N=3,K=2,如果面值分別爲1分、4分,則在1分~6分之間的每一個郵資值都能得到(當然還有8分、9分和12分);如果面值分別爲1分、 3分,則在1分~7分之間的每一個郵資值都能得到。可以驗證當N=3,K=2時,7分就是可以得到的連續的郵資最大值,所以MAX=7,面值分別爲1分、 3分。
輸入
一行,兩個數N、K
輸出
兩行,第一行升序輸出設計的郵票面值,第二行輸出“MAX=xx”(不含引號),其中xx爲所求的能得到的連續郵資最大值。
樣例輸入
3 2
樣例輸出
1 3 MAX=7
思路:
假如現在已經得到選擇了N張郵票,並且各種郵票價值之後爲sum,那麼我們可以用完全揹包求出dp[j],即湊出j元至少需要的郵票數目。
首先要考慮到價值爲1的郵票一定要選,因爲只有選1,才能湊出1呀。然後我們進行搜索,有三個狀態,現在已經選擇的郵票數,最大符合題意的值,選擇的郵票價值之和。
每次枚舉從上一次枚舉的郵票價值tmp[x]+1,到maxx+1,爲什麼不是maxx+2,因爲在上一種狀態maxx+1就湊不出,這次若選maxx+2,那麼maxx+1就更湊不出來了。
每次搜索進行dp一次,求出現在的符合題意的值。
代碼:
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#include<string.h>
#include<queue>
#include<stack>
#include<cstdio>
#include<cmath>
#include <stdlib.h>
#include<stack>
using namespace std;
const int maxn=100000+10;
#define mod 1000000007
#define INF 0x3f3f3f3f
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
int n,k;
int dp[maxn];
int tmp[maxn];
int ans[maxn];
int dpp(int N,int sum)
{
memset(dp,333,sizeof(dp));
dp[0]=0;
rep(i,1,N)
{
rep(j,tmp[i],sum*n)
{
dp[j]=min(dp[j],dp[j-tmp[i]]+1);
}
}
rep(i,1,sum*n)
{
if(dp[i]>n)return i-1;
}
return sum*n;
}
int mans;
void dfs(int x,int maxx,int s)
{
if(x==k)
{
if(maxx>mans)
{
mans=maxx;
rep(i,1,k)
{
ans[i]=tmp[i];
}
}
return ;
}
rep(i,tmp[x]+1,maxx+1)
{
tmp[x+1]=i;
int ms=dpp(x+1,s+i);
dfs(x+1,ms,s+i);
}
return ;
}
int main()
{
cin>>n>>k;
mans=0;
tmp[1]=1;
dfs(1,n,1);
rep(i,1,k)
{
cout<<ans[i]<<" ";
}
cout<<endl;
cout<<"MAX="<<mans<<endl;
return 0;
}