1. 程式人生 > >uva 10313 整數拆分——硬幣湊價

uva 10313 整數拆分——硬幣湊價

給你一個價格n,求在指定使用的硬幣個數範圍內付款的方案數,後面可能給你邊界a,b,也可能不給,不給的話個數是1-n,給一個a就是1-a,給兩個是a-b

直接開二維陣列揹包的話會算重複,比如湊6的話,1、2、3,,2、1、3,3、1、2,一種方案就數了三遍,需加一維限制大小,dp[i][j][k]中用j個硬幣湊成價格i,j個硬幣中最大的硬幣面值最大是k,dp[i][j][k]+=dp[i-k][j-1][t], 1<=t<=k.但這樣規模會太大

這個題目涉及到一個結論,用不超過j個硬幣湊出面值i的方案種數,是和用面值不超過j的硬幣湊出面值i的方案種數是相同的。說得再數學一點,就是整數i拆分成不超過j個整數的拆分數,是和整數i拆成若干個值不超過j的整數的拆分數是相同的。具體的證明用到了Ferrers影象的性質。

    這樣的話我們就可以取一個二維陣列f[i][j]表示用面值不超過j的硬幣湊出面值i的方案的種數,那麼如果我使用了面值j,對應方案種數就應該加上f[i-j][j],如果我們不使用面值j,那麼對應的方案種數就應該加上f[i][j-1]。也就是說狀態轉移方程為f[i][j]= f[i-j][j]+ f[i][j-1]。

#include<stdio.h>
#include<string.h>
#include<iostream>
#define N 310
using namespace std;
long long f[N][N];
int n,a,b;
char s[200];
int main()
{
    int i,j,k,l;
    memset(f,0,sizeof(f));
    /*
    for(i=0;i<=300;i++)
        f[0][i]=1;
    for(i=0;i<=k;i++)
    {
        for(j=1;j<=i;j++)
        {
            if(i>=j)
                f[i][j]+=f[i-j][j]; //用j
            f[i][j]+=f[i][j-1];//沒用j
        }
    }
    這樣不對,j比i大的時候,f[i][j]還是0,即每次用了j時f[i][j]加上的情況f[i-j][j]一直是0,少算了,f[i][j],當i比j小的時候依然有用
    */
f[0][0]=1;
k=300;
    for(i=0;i<=k;i++)
    {
        for(j=1;j<=k;j++)
        {
            if(i>=j)
                f[i][j]+=f[i-j][j]; //用j
            f[i][j]+=f[i][j-1];//沒用j
        }
    }
    while(gets(s)!=NULL)
    {
        a=b=-1;
        sscanf(s,"%d%d%d",&n,&a,&b);
        //sscanf中沒有讀取成功將不會改變原值
        if(a==-1&&b==-1)
            a=1,b=n;
        else if(a!=-1&&b==-1)
            b=a,a=1;
        printf("%lld\n",f[n][b]-f[n][a-1]);
    }
    return 0;
}
百度百科

Ferrers影象

影象概念

一個從上而下的n層格子,mi 為第i層的格子數,當mi>=mi+1(i=1,2,,n-1) ,即上層的格子數不少於下層的格子數時,稱之為Ferrers影象。[1]

影象性質

(1)每一層至少有一個格子;
  (2)第一行與第一列互換,第二行與第二列互換,…,所得到的圖象仍然是Ferrers圖象,這兩個 Ferrers圖象稱為是一對共軛的Ferrers圖象。 性質(2)

性質(2)

影象應用

(a) 整數n拆分成k個數的和的拆分數,和數n拆分成最大數為k的拆分數相等。因整數n拆分成k個數的和的拆分可用一k行的影象表示。所得的Ferrers影象的共軛影象最上面一行有k個格子。例如:
24=6+6+5+4+3 5個數,最大數為6 再如: 24=5+5+5+4+3+2 6個數,最大數為5 (b) 整數n拆分成最多不超過m個數的和的拆分數,和n拆分成最大不超過m的拆分數相等。 理由與(a)類似。 (c) 整數n拆分成互不相同的若干奇數的和的拆分數,和n拆分成自共軛的Ferrers影象的拆分數相等。 設n=(2n1+1)+(2n2+1)+……+2(nk+1),其中n1>n2>……nk。 構造一個Ferrers影象,其第一行,第一列都是n1+1格,對應於2n1+1,第二行,第二列各n2+1格,對應於2n2+1。依此類推。由此得到的Ferrrers影象是共軛的。反過來也一樣。 例如:17=9+5+3 對應的Ferrers影象為: