Vijos P1179 郵票面值設計(動態規劃,深搜)

P1179郵票面值設計

描述

給定一個信封,最多隻允許粘貼N張郵票,計算在給定M(N+M<=10)種郵票的情況下(假定所有的郵票數量都足夠),如何設計郵票的面值,能得到最大max ,使得1~max之間的每一個郵資值都能得到。

例如,N=3,M=2,如果面值分別爲1分、4分,則在l分~6分之間的每一個郵資值都能得到(當然還有8分、9分和12分):如果面值分別爲1分、3分,則在1分~7分之間的每一個郵資值都能得到。可以驗證當N=3,M=2時,7分就是可以得到連續的郵資最大值,所以MAX=7,面值分別爲l分、3分。

樣例輸入:共一行,兩個整數,分表爲N與M的值。

格式

輸入格式

一行,分別爲N,M。

輸出格式

兩行。

第一行爲m種郵票的面值,按升序排列,各數之間用一個空格隔開。

第二行爲最大值。

如果有多解,輸出字典序最大的一個。

樣例1

樣例輸入1[複製]

3 2

樣例輸出1[複製]

1 3
MAX=7

限制

各個測試點1s

來源

NOIP1999

思路

1)n枚郵票,m種面額,要使得郵資連續,顯然1是必須的
2)樣例中3枚郵件,有兩種面額,一種爲1,要求另一種面額,使得連續的郵資數最多。顯然由面額1,可以得到1,2,3的郵資,因爲只有3枚,所以只能連續到3,如果要得到更大的郵資,則另一種面額數一定在2,3,4之間,也就是a[i]+1~a[i]*n+1
3)若面值爲1,2,則有:
    1=1
    2=2
    3=1+2
    4=2+2
    5=2+2+1
    6=2+2+2
    7=2+2+2+1(已經超過了給定的枚數)
故:最多連續到6
4)若面值爲1,3,則有
1=1
2=1+1
3=3
4=3+1
5=3+1+1
6=3+3
7=3+3+1
8=3+3+1+1(超過了指定枚數)
最多連續到7
5)若面值爲1,4,則有
1=1
2=1+1
3=1+1+1
4=4
5=4+1
6=4+1+1
7=4+1+1+1(超過了三枚)
最多連續到6
6)綜上,顯然需要用DFS來搜索郵件的m種面額,從1開始依次搜索,對於每一個新的面額,都要判斷一下所能得到的最大連續值
7)主函數
輸入n,m
開始搜索第1種面額dfs(1)
輸出各種面額
輸出最大的連續數值
8)dfs(x)的實現
搜索範圍:前一種面額+1~最大連續值+1
搜索條件:不超過m
相關操作:如果得到更大的連續值,則一時更新最大連續值cnt,同時保存所有的面額ans[i]
提前處理:另寫函數cal(num)實現num種郵票所能得到的最大連續值
9)cal(num)計算num種郵票的最大連續值
判斷的辦法,其實就是從0開始,每次加1,逐個數地計算所需要的最少郵票數,如果在n的範圍內,就繼續,如果某一郵資需要量超過n枚郵票,則意味着不連續

代碼

#include <iostream>
using namespace std;
int dp[1010],n,m,arr[11],cnt,ans[11];
int cal(int num)		//計算num種郵票所能形成的最大連續面額 
{
    if(!num)return 0;
    for(int i=0;i<1010;i++)
		dp[i]=100000;		//賦初值勤 
    dp[0]=0;				
    int x=0;
    while(dp[x]<=n)			//如果郵資x的最少郵票數不超過n枚 
    {
        for(int i=1;i<=num;i++)
            dp[x+arr[i]]=min(dp[x+arr[i]],dp[x]+1);//利用動規揹包求每一種郵資所需的郵票數 
        x++;
    }
	return x-1;
}
inline void dfs(int x)		//深搜第x種面額 
{
	int now=cal(x-1);		//計算前x-1種郵票成形成的最大連續面額 
	if(x<=m)								//如果還沒到第m種 
	    for(int i=now+1;i>=arr[x-1];i--)	//在a[i]*n+1~a[i]+1中找下一個面額 
	    {
	        arr[x]=i;						//第x種面額爲i 
	        dfs(x+1);						//深搜第x+1種面額 
	    }    
	else
        if(now>cnt)						//如果超過了最大連續值 
        {
            cnt=now;					//更新最大連續值 
            for(int i=1;i<=m;i++)		//保存各面額 
                ans[i]=arr[i];
        }
}
int main()
{
    cin>>n>>m;				//最多n張郵票,m種 
    dfs(1);					//深搜第一種面額 
    for(int i=1;i<m;i++)   //輸出前m-1種面額 
        cout<<ans[i]<<' ';
    cout<<ans[m]<<endl;		//輸出最後一種面額 
    cout<<"MAX="<<cnt;		//輸出最大值 
    return 0;
} 


發佈了56 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章