Coin Count——ACM生成函數的應用

 
NEUOJ 1050 Coin Count----Generate Function
一,原題及數據  
Problem 1050 - Coin Counting
Time Limit:1000MS  Memory Limit:65536KB
Total Submit:76  Accepted:10
Description
You are given n coins, and you can take r coins of them. But before taking them, you have to tell how many different combinations can be.
May be you are given many r, so you must tell the answer for each r.
 
Input
Input consists of less than 100 test cases. Each test case begins with two integers n (0 < n &lt;= 50), m (0 &lt;= m &lt;= n). The next line will
contain the values (numbers in the range 1 to n) of the n coins you are to choose from. Two coins with the same value are considered equivalent.
Then in the last line for that test case, you'd have m values for r. There will be a single space separating two consecutive numbers in a line.
Input is terminated by a test case where n=0, you must not process this test case.
 
Outpu
tFor each test case, print the test case number. And for each query number r, print the number of different combinations that can be formed
if r coins are taken from the given n coins. You can assume that for all input cases, the output will always fit in a 64bit unsigned integer and (0&lt;=r&lt;=n).
 
Sample Input5 2
1 2 3 4 5
1 2
4 1
1 1 3 4
2
0 0
Sample Output
Case 1:
5
10
Case 2:
4
二,思路及示例分析
這個題我做出來還是很有感覺的,雖然比較簡單。
這個題的突破點就在題目給的提示中,n個任意麪值的硬幣,選擇r塊可以組成多少種不同的面值。這種計數的模型類似C(n,r)的式子,既從n個元素中選擇r個元素,問有多少種選法。
這種類型的就十分適合用生成函數來解決。用生成函數解決問題關鍵是生成函數的設計。這個題目的設計就是要讓x^r的係數表示,從n個硬幣中選取r個硬幣可以組合的面值數。
例如,x 表示選擇1枚的面值數,x^2,表示選擇2枚後的面值數。
生成函數的一般形式是:
F(x)=(1+a1x+a2x^2+..+anx^n)(1+b1x+...+bnx^n)...(1+...+kn*x^n)
      =1+q1x+q2x^2+...+qnx^n+...   ——(1)
有幾個不同的數一般就有幾個不同的因子。
按照這個思路,思考題目給的例子。
例1。因爲5個數選1個的種數爲5,故該例中F(x)中一次項爲5x。同理,二次項爲10x^2。係數剛好爲C(5,1),C(5,2),對應爲(x+1)^5的次數。
故猜測F(x)=(1+x)(1+x)(1+x)(1+x)(1+x)=(1+x)^5。
可惜的是這個式子,不適合例2。如果將這個式子應用到例2則有F(x)=(1+x)^3。很顯然x^2的係數爲C(3,2)!=4。爲什麼?原因是出現了重複的數1。
在選兩個數的過程中,1可以不選,可以被選1次,可以被選2次。一個因子裏可以用x^k表示x有k次被選的機會。
由於例2中1有2次被選的機會,4,5各有1次被選的機會。這樣例2的生成函數就可以設計爲F(x)=(1+x+x^2)(1+x)(1+x)。對這個式子展開,顯然x^2的係數爲4。
假設這個題的輸入數據爲a1,a2,a3,...,a^n,其中ai重複出現的次數爲ki(i>=1,k&gt;=1)。
由此該題的生成函數就可以設計爲:
F(x)=(1+x+...+x^k1)(1+x+...+x^k2)....(1+x+...+x^kn)。
因此這個題可以化爲統計ai出現的次數,展開F(x),求x^r的係數問題。
三,程序代碼 
#include<stdio.h>
#include<iostream>

using namespace std;
const int lmax=3000;
int e[lmax+1];//i e

unsigned long long A1[lmax+1],A2[lmax+1];//    

int n;
int t,q;

void initn()
{

    n=0;
    for(int i=1;i<=t;i++)
    if(e[i])
    n+=e[i];
}// max e

void generateFunction()
{
int i,j,k;
for(i=0;i<=n;i++)
{
A1[i]=A2[i]=0;
}
for(i=0;i<=e[1];i++)// 1+x+...+x^count[k]
A1[i]=1;
        for(i=2;i<=n;i++)
{
for(j=0;j<=n;j++)
for(k=0;k<=e[i]&&k+j<=n;k++)
{
                                A2[j+k]+=A1[j];
}
for(j=0;j<=n;j++)
{
A1[j]=A2[j];
A2[j]=0;
}
}
}
int main()
{
int a,i,j=0;
while(scanf("%d%d",&t,&q)!=EOF,t+q)
{
     memset(e,0,sizeof(e));
     i=0;
     while(i<t)
     {
         scanf("%d",&a);
         e[a]++;
         i++;
     }
     initn();
     generateFunction();
     if(q)
     printf("Case %d:\n",++j);
     while(q--)
     {
     scanf("%d",&a);
     printf("%llu\n",A1[a]);
     }
}
return 0;
}
四,總結
1,某些計數問題可以用生成函數來解決。
2,生成函數的問題中關鍵是生成函數的設計,其設計可以結合具體的示例數據和常見的生成函數來設計。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章