ACM训练赛--递推专题
1001: Buy the Ticket
Problem Description
The "Harry Potter and the Goblet of Fire" will be on show in the next few days. As a crazy fan of Harry Potter, you will go to the cinema and have the first sight, won’t you?
Suppose the cinema only has one ticket-office and the price for per-ticket is 50 dollars. The queue for buying the tickets is consisted of m + n persons (m persons each only has the 50-dollar bill and n persons each only has the 100-dollar bill).
Now the problem for you is to calculate the number of different ways of the queue that the buying process won't be stopped from the first person till the last person.
Note: initially the ticket-office has no money.
The buying process will be stopped on the occasion that the ticket-office has no 50-dollar bill but the first person of the queue only has the 100-dollar bill.
Input
The input file contains several test cases. Each test case is made up of two integer numbers: m and n. It is terminated by m = n = 0. Otherwise, m, n <=100.
Output
For each test case, first print the test number (counting from 1) in one line, then output the number of different ways in another line.
Sample Input
3 0
3 1
3 3
0 0
Sample Output
Test #1:
6
Test #2:
18
Test #3:
180
Source
HUANG, Ninghai
?
題目分析:
?
題目大意:
電影院買票,收銀臺沒有零錢,而排隊買票的人手里拿著的都是100元或是50元,每張票50元,給出拿100或50的各自人數,求出有幾種排列方法使得收銀臺不會因找不出錢而停止!
?
我的思路:
設m張50元n張100元時的排列方法有f(m,n)種,總人數為m+n;當總人數為m+n-1時,有兩種情況:
(1)m少1。此時必須要滿足m>n(若m=n,則m-1< P>
(2)n少1。排列方法有f(m,n-1)種。當n-1多1時,同理有n*f(m,n-1)種方法。
由以上兩種情況得到遞推公式:
當m=n時,f(m,n)=n*f(m,n-1);
當m>n時,f(m,n)=m*f(m-1,n)+n*f(m,n-1);
當m<n時,f(m,n)=0.
下一步就要確定初始條件:
當m=1, n=0時,f(m,n)=1; 當m=1, n=1時,f(m,n)=1.
另外,由于本題的數據比較大,必須要用高精度,而且遞歸會超時,要用數組來保存數據。那么,選用哪種類型的數組比較好呢?很顯然,本題涉及到很大的運算量,用整型的數組比較好。于是,用f[m][n][]代表f(m,n)。
?
以下是我的代碼:
?
#include<stdio.h>
#define c 51????????????????????? //定義數組的長度
#define d 100000000??????? //定義常量,用于整型數組的數據處理
int main()
{
??? int m,n,i,j,k,t=1,temp=0,f1,f2;
??? __int64 ff;
??? int f[101][101][c]={0};???????????????????????? //數組初始化為0
??? f[1][0][0]=1;????????????????????????????????????????? //初始條件
??? f[1][1][0]=1; ??????????????????????????????????????? //初始條件
??? for(i=2;i<=100;i++)
????? for(j=0;j<=i;j++)
??????? {
???????? for(k=0;k<c;k++)
?????????? if(j==i)
?????????? {
??????????? ff=(__int64)j*f[i][j-1][k]+temp;?? //注意,當數據比較大時,
??????????? if((ff>d)&&(k<c-1))??????????????????? // j*f[i][j-1][k]會超出整型的范圍,
??????????? {?????????????????????????????????????????????????? //故用(__int64)強制類型轉換
????????????? temp=ff/d;???????????????????????????????
????????????? ff%=d;
????????????? f[i][j][k]=(int)ff;
??????????? }
??????????? else f[i][j][k]=(int)ff,temp=0;
?????????? }
?????????? else
?????????? {
??????????? ff=(__int64)i*f[i-1][j][k]+(__int64)j*f[i][j-1][k]+temp;
??????????? if((ff>d)&&(k<c-1))
??????????? {
????????????? temp=ff/d;
????????????? ff%=d;
????????????? f[i][j][k]=(int)ff;
??????????? }
??????????? else f[i][j][k]=(int)ff,temp=0;
?????????? }
?? ??????}
??? while(scanf("%d%d",&m,&n)!=EOF&&((m!=0)||(n!=0)))
??? {
?????? printf("Test #%d:\n",t++);
?????? for(i=c-1;i>0;i--)if(f[m][n][i]!=0)break;? //去掉數據中無效的0
?????? printf("%d",f[m][n][i]);
?????? for(j=i-1;j>=0;j--)printf("%08d",f[m][n][j]);??????? //%08d中08表示輸出的數
?????? printf("\n");?????????????????????????????????????????????????????????? //據占8位,這是因為模
??? }???????????????????????????????????????????????????????????????????????????????? //100000000后,保存的數據
??? return 0;????????????????????????????????????????????????????????????????????? //只有8位
}?
PS:此題用了個3維的數組,占用的空間比較大,可以考慮用兩個2維的數組代替。另外,此題用C++提交會超時且堆棧溢出,而用G++提交則不會,這說明本代碼不優,同時也間接說明了用G++提交代碼的好處。
?
?
?
?
?
?
?
1002:Tri Tiling
Problem Description
In how many ways can you tile a 3xn rectangle with 2x1 dominoes? Here is a sample tiling of a 3x12 rectangle.
?
?Input
Input consists of several test cases followed by a line containing -1. Each test case is a line containing an integer 0 ≤ n ≤ 30.
Output
For each test case, output one integer number giving the number of possible tilings.
Sample Input
2
8
12
-1
Sample Output
3
153
2131
Source
University of Waterloo Local Contest 2005.09.24
?
題目分析:
?
題目大意:
用2*1大小的多米諾骨排蓋3*n的矩形,問有多少種蓋法。
?
我的思路:
首先可以看出,當n為奇數時,無論怎么蓋也不會蓋成3*n的矩形,故只需考慮n為偶數即可。可以將此題抽象為一個3*n的矩陣,用f(a,b,c)代表有多少種蓋法,其中a,b,c分別代表第1、2、3行的元素個數,由此推導遞歸公式。假設第n列已蓋好,那么它可由以下幾種情況組成:
(1)??? 橫放3個,此時f(a,b,c)=f(a-2,b-2,c-2);
(2)??? 豎放1個,橫放1個,此時f(a,b,c)=f(a-1,b-1,c-2);
(3)??? 橫放1個,豎放1個,此種情況與(2)對稱,故仍可用f(a,b,c)=f(a-1,b-1,c-2)。
?
于是得遞推公式:
當a=b=c時,f(a,b,c)= 2*f(a-2,b-1,c-1)+f(a-2,b-2,c-2);
當a<b且b=c時,f(a,b,c)= f(a,b-1,c-1)+f(a-2,b-2,c-2).
(由于f(a-2,b-1,c-1)產生了另一種情況:a<b且b=c,此時它由f(a,b-1,c-1)和f(a-2,b-2,c-2)兩種情總組成。f(a,b-1,c-1)表示該情況是由第二第三排豎放一個產生的;f(a-2,b-2,c-2)表示該情況是由3個橫放產生的,當然第一排的橫放要比第二第三排縮一格。)
下一步就是要確定初始條件:
當a=b=c=0時,f(a,b,c)=1.因為一列也不排也算是一種方法。
當a或b或c中有一個小于0時,f(a,b,c)=0.因為這種情況不可能存在。?
以下是我的代碼:
?
#include<stdio.h>
int f(int a,int b,int c)
{
??? if(a*b*c==0)return 1;
??? else if(a<0||b<0||c<0)return 0;
??? else if(a==b&&b==c)return 2*f(a-2,b-1,c-1)+f(a-2,b-2,c-2);
??? else if(a<b&&b==c)return f(a,b-1,c-1)+f(a-2,b-2,c-2);
}
int main()
{
??? int n,s;
??? while(scanf("%d",&n)!=EOF&&n!=-1)
??? {
????? if(n%2==0)s=f(n,n,n);
????? else s=0;
????? printf("%d\n",s);
??? }
??? return 0;
}?
PS:此題也可以根據遞推用數組解決,以減少題目用時。
?
?
?
?
?
?
1003:漢諾塔II
Problem Description
經典的漢諾塔問題經常作為一個遞歸的經典例題存在。可能有人并不知道漢諾塔問題的典故。漢諾塔來源于印度傳說的一個故事,上帝創造世界時作了三根金剛石柱子,在一根柱子上從下往上按大小順序摞著64片黃金圓盤。上帝命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一回只能移動一個圓盤。有預言說,這件事完成時宇宙會在一瞬間閃電式毀滅。也有人相信婆羅門至今仍在一刻不停地搬動著圓盤。恩,當然這個傳說并不可信,如今漢諾塔更多的是作為一個玩具存在。Gardon就收到了一個漢諾塔玩具作為生日禮物。
Gardon是個怕麻煩的人(恩,就是愛偷懶的人),很顯然將64個圓盤逐一搬動直到所有的盤子都到達第三個柱子上很困難,所以Gardon決定作個小弊,他又找來了一根一模一樣的柱子,通過這個柱子來更快的把所有的盤子移到第三個柱子上。下面的問題就是:當Gardon在一次游戲中使用了N個盤子時,他需要多少次移動才能把他們都移到第三個柱子上?很顯然,在沒有第四個柱子時,問題的解是2^N-1,但現在有了這個柱子的幫助,又該是多少呢?
Input
包含多組數據,每個數據一行,是盤子的數目N(1<=N<=64)。
Output
對于每組數據,輸出一個數,到達目標需要的最少的移動數。
Sample Input
1
3
12
Sample Output
1
5
81
Author
Gardon
Source
Gardon - DYGG's contest 2
?
題目分析:
?
我的思路:
剛開始沒什么思路,于是分析數據,發現了下面的規律:
a[1]=1;
a[2]=a[1]+2;a[3]=a[2]+2;(2個加2^1)
a[4]=a[3]+4;a[5]=a[4]+4;a[6]=a[5]+4;(3個加2^2);
…………………………………………(4個加2^3);
……
?
以下是我的代碼:
?
#include<stdio.h>
#include<math.h>
int main()
{
??? int n,i,j,k,sum;
??? int f;
??? while(scanf("%d",&n)!=EOF)
??? {
????? k=2;
????? for(i=1;i<=n;i++)
????? {
??????? if(i==1)f=1,sum=1;
??????? else
??????? {
????????? for(j=k;sum<i;j++)sum+=j;
????????? k=j;
????????? f+=(int)pow(2,j-2);
??????? }
????? }
????? printf("%d\n",f);
??? }
??? return 0;
}?
?
?
?
?
?
?
1004:三角形
Problem Description
用N個三角形最多可以把平面分成幾個區域?
Input
輸入數據的第一行是一個正整數T(1<=T<=10000),表示測試數據的數量.然后是T組測試數據,每組測試數據只包含一個正整數N(1<=N<=10000).
Output
對于每組測試數據,請輸出題目中要求的結果.
Sample Input
2
1
2
Sample Output
2
8
Author
Ignatius.L
?
題目分析:
?
我的思路:
第n個三角形每條邊最多與2*(n-1)條邊相交。對于每條邊,它所截出的區域(不算第n個三角形的角)有2*(n-1)-1個,于是3條邊可截出6*(n-1)-3個區域,再加上3個角即可多出6*(n-1)個區域。
于是得遞推公式:f(n)=f(n-1)+ 6*(n-1)
初始條件是:f(1)=2
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
?????? int t,n;
?????? __int64 f;
?????? while(scanf("%d",&t)!=EOF)
?????? while(t--)
?????? {
????????????? scanf("%d",&n);
????????????? f=2;
????????????? while(n!=1)f+=6*(n-1),n--;
????????????? printf("%I64d\n",f);
?????? }
?????? return 0;
}?
PS:由以上遞推公式可得到最終公式,使得代碼更加優化,這里就不再細說了。
另外,平面是2維的,它跟二次多項式a*x^2+b*x+c有關,我們可以用1、2、3個平面的情況推出系數a,b,c,這樣同樣可以得到最終公式!
?
?
?
?
?
?
1005:下沙的沙子有幾粒?
Problem Description
2005年11月份,我們學校參加了ACM/ICPC 亞洲賽區成都站的比賽,在這里,我們獲得了歷史性的突破,盡管只是一枚銅牌,但獲獎那一刻的激動,也許將永遠銘刻在我們幾個人的心頭。借此機會,特向去年為參加ACM亞洲賽而艱苦集訓了近半年的各位老隊員表示感謝。
實際上,除了獲獎以外,在這次比賽期間還有一件事也讓我們記憶深刻。那是比賽當天等待入場的時候,聽到某個學校的一個隊員在說:“有個學校的英文名很有意思,叫什么Hangzhou Dianzi University”. 哈哈,看來我們學校的英文名起的非常好,非常吸引人呀。
不過,事情的發展誰也沒有料到,隨著杭電英文校名的這一次曝光,影響越來越大,很多人開始對杭電英文校名進行研究,不久以后甚至還成立了一個專門的研究機構,叫做“HDU 校名研究會”。并不斷有報道說-相-當-多的知名科學家改行,專門對該問題進行研究,學術界稱之為“杭電現象”。很多人在國際知名期刊上發表了研究論文,這其中,尤以中國超級女科學家宇春小姐寫的一篇研究報告最為著名,報告發表在science上,標題是“杭電為什么這樣紅?” 文中研究發現:Hangzhou Dianzi University這個校名具有深刻的哲學思想和內涵,她同時提出了一個大膽的猜想:“假定一個字符串由m個H和n個D組成,從左到右掃描該串,如果字符H的累計數總是不小于字符D的累計數,那么,滿足條件的字符串總數就恰好和下沙的沙粒一樣多。”
這就是當今著名的“宇春猜想”!
雖然還沒能從數學上證明這個猜想的正確性,但據說美國方面在小布什的親自干預下,已經用超級計算機驗證了在(1<=n<=m<=1000000000000)時都是正確的。my god! 這是一個多么偉大的猜想!雖然我們以前總說,21世紀是屬于中國的,可還是沒想這一天來的這么早,自豪ing... + 感動ing...
感動和自豪之余,問題也來了,如果已知m和n的值,請計算下沙的沙粒到底有多少。
Ps:
1. 中國有關方面正在積極行動,著手為宇春小姐申報諾貝爾獎。
2、“宇春猜想”中提到的H和D組成的字符串現在被學術界成為“杭電串串”(“杭電串串”前不久被一個賣羊肉串的注冊了商標,現在我校正在積極聯系買斷,據說賣方的底價是1000萬歐元,絕不打折,看來希望不大,sigh...)
Input
輸入數據包含多個測試實例,每個占一行,由兩個整數m和n組成,m和 n 分別表示字符串中H和D的個數。由于我們目前所使用的微機和老美的超級計算機沒法比,所以題目給定的數據范圍是(1<=n<=m<=20)。
Output
對于每個測試實例,請輸出下沙的沙粒到底有多少,計算規則請參考“宇春猜想”,每個實例的輸出占一行。
Sample Input
1 1
3 1
Sample Output
1
3
Author
lcy
Source
HDU 2006-4 Programming Contest
?
題目分析:
?
?
我的思路:
設由m個H和n個D組成的串有f(m,n)個,它是由m+n-1個再加上一個H或D組成的。
于是得遞推公式:
f(m,n)=f(m-1,n)+f(m,n-1);
下一步確定初始條件:
f(0,1)=0; f(1,0)=1.
另外,當m<n時,f(m,n)=0; 當m=0時,f(m,n)=0; 當n=0時,f(m,n)=1.?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? int n,m,i,j;
??? __int64 f[22][22];
??? while(scanf("%d%d",&m,&n)!=EOF)
??? {
?????? for(i=0;i<=m;i++)
??????? for(j=0;j<=n;j++)
??????? {
????????? if((i==0)||(i<j))f[i][j]=0;
????????? else if(j==0)f[i][j]=1;
????????? else f[i][j]=f[i-1][j]+f[i][j-1];
??????? }
?????? printf("%I64d\n",f[m][n]);
??? }
??? return 0;
}?
PS:本題與1001類似,但不同的是,1001中拿50塊錢的人是不同的,所以交換位置也是一種排法;而本題中m個H是相同的,所以加進的H無需與前m-1個H交換位置。另外,本題數據量比較小,因此更加簡單!
?
?
?
?
?
?
1006:錢幣兌換問題
Problem Description
在一個國家僅有1分,2分,3分硬幣,將錢N兌換成硬幣有很多種兌法。請你編程序計算出共有多少種兌法。
Input
每行只有一個正整數N,N小于32768。
Output
對應每個輸入,輸出兌換方法數。
Sample Input
2934
12553
Sample Output
718831
13137761
Author
SmallBeer(CML)
Source
杭電ACM集訓隊訓練賽(VII)
?
?
題目分析:
?
我的思路:
假設數N/3得到的商為S,則可以分成S+1種大情況(即0~S個3)討論,對于每種大情況i (0<=i<=S),設(N-i*3)/2=W, 則又可以分為W+1種小情況(即0~W個2),而每個小情況中2的個數X則為X種兌法,因為3和2確定后,1也確定了,此時即為一種兌法。
?
我的代碼如下:
?
#include<stdio.h>
int main()
{
??? int i,j,n,tempi,tempj;
??? __int64 f;
??? while(scanf("%d",&n)!=EOF)
? ??{
????? tempi=n/3;
????? f=0;
????? for(i=0;i<=tempi;i++)f+=(n-i*3)/2+1;
????? printf("%I64d\n",f);
??? }
??? return 0;
}?
?
?
?
1007:獻給杭電五十周年校慶的禮物
Problem Description
或許你曾經牢騷滿腹
或許你依然心懷憂傷
或許你近在咫尺
或許你我天各一方
對于每一個學子
母校
永遠航行在
生命的海洋
今年是我們杭電建校五十周年,這是一個值得祝福的日子。我們該送給母校一個怎樣的禮物呢?對于目前的大家來說,最好的禮物當然是省賽中的好成績,我不能參賽,就送給學校一個DOOM III球形大蛋糕吧,這可是名牌,估計要花掉我半年的銀子呢。
想象著正式校慶那一天,校長親自操刀,把這個大蛋糕分給各地趕來祝賀的校友們,大家一定很高興,呵呵,流口水了吧...
等一等,吃蛋糕之前先考大家一個問題:如果校長大人在蛋糕上切了N刀(校長刀法極好,每一刀都是一個絕對的平面),最多可以把這個球形蛋糕切成幾塊呢?
做不出這個題目,沒有蛋糕吃的!
為-了-母-校-,為-了-蛋-糕-(不是為了DGMM,楓之羽最會浮想聯翩...),加-油-!
Input
輸入數據包含多個測試實例,每個實例占一行,每行包含一個整數n(1<=n<=1000),表示切的刀數。
Output
對于每組輸入數據,請輸出對應的蛋糕塊數,每個測試實例輸出一行。
Sample Input
1
2
3
Sample Output
2
4
8
Author
lcy
Source
杭電ACM集訓隊訓練賽(VIII)
?
?
題目分析:
?
我的思路:
這其實是考我們n個平面最多可以把空間分成幾個部分的問題。
使第n個平面與前面n-1個平面都相交,且交線都不重合,那么n-1條直線最多可以把平面劃分成為n(n-1)/2+1個部分
于是得遞推公式f(n)=f(n-1)+n(n-1)/2
初始條件:f(1)=2
?最后可以推出公式:f(n)=(n^3+5n+6)/6
?
我的代碼如下:
?
#include<stdio.h>
int main()
{
??? int n;
??? while(scanf("%d",&n)!=EOF)
????? printf("%d\n",(n*n*n+5*n+6)/6);
??? return 0;
}?
PS:空間是3維的,它跟三次多項式a*x^3+b*x^2+c*x+d有關,我們可以由4種特殊情況(例如x=1、2、3、4)列四個方程,解出系數a,b,c,d,從而求出最終公式!
?
?
?
?
?
?
1008:Children’s Queue
Problem Description
There are many students in PHT School. One day, the headmaster whose name is PigHeader wanted all students stand in a line. He prescribed that girl can not be in single. In other words, either no girl in the queue or more than one girl stands side by side. The case n=4 (n is the number of children) is like
FFFF, FFFM, MFFF, FFMM, MFFM, MMFF, MMMM
Here F stands for a girl and M stands for a boy. The total number of queue satisfied the headmaster’s needs is 7. Can you make a program to find the total number of queue with n children?
Input
There are multiple cases in this problem and ended by the EOF. In each case, there is only one integer n means the number of children (1<=n<=1000)
Output
For each test case, there is only one integer means the number of queue satisfied the headmaster’s needs.
Sample Input
1
2
3
Sample Output
1
2
4
Author
SmallBeer (CML)
Source
杭電ACM集訓隊訓練賽(VIII)
?
題目分析:
?
題目大意:
一個隊伍中有n個學生,但規定女生不能單獨站,也就是說,要么隊伍中沒有女生,要么有兩個或兩個以上的女生站在一起(這是保護弱勢力的體現!)。問有多少這樣的隊伍。
?
我的思路:
設n個學生生按規則排成的隊列有f(n)種,那么當總人數少一個時會是什么情況呢?顯然,要么少一個男的,要么少一個女的。故有如下情況:
(1)??? 少一個男的,也就是說,第n個加進去的是男生。此時,隊列n-1只需按規則站好即可,故有f(n-1)種方法。
(2)??? 少一個女的,也就是說,第n個加進去的是女生。此時,前面的肯定不能是男生,因為后面加進去的女生只有一個,不符合規則,因此第n-1個(也就是前1個)必須是女生。若n-2個是按規則站好的,則有f(n-2)種方法;若n-2個不是按規則站好的(因為第n-1,第n個是女生,所以第n-2個可以是女生,第n-3個可以是男生。當沒加進第n-1和第n個女生的時候,這是不合規則的),即第n-2個是女生,第n-3個是男生,此后第n-4個必須按規則站好,故有f(n-4)種方法。
于是得遞推公式:
f(n)=f(n-1)+f(n-2)+f(n-4);
下一步就要確定初始條件:
由于遞推公式有f(n-1)、f(n-2)和f(n-4),故必須給出f(1)、f(2) 、f(3)和 f(4)
由題意得:f(1)=1;f(2) =2;f(3)=4; f(4)=7。
?
注意:由于本題數據量比較大,必須要用高精度,同時用數組保存結果來代替遞歸。
下面是我的代碼:
?
#include<stdio.h>
#define c 31
#define d 100000000
int main()
{
??? int n,i,j;
??? int f[1000][c]={0};
??? f[0][0]=1;
??? f[1][0]=2;
??? f[2][0]=4;
??? f[3][0]=7;
??? for(i=4;i<1000;i++)
??? {
????? for(j=0;j<c;j++)
??????? f[i][j]=f[i-1][j]+f[i-2][j]+f[i-4][j];
????? for(j=0;j<c-1;j++)
??????? if(f[i][j]>d)
??????? {
????????? f[i][j+1]+=f[i][j]/d;
????????? f[i][j]%=d;
?????? ?}
??? }
??? while(scanf("%d",&n)!=EOF)
??? {
????? for(i=c-1;i>0;i--)if(f[n-1][i]!=0)break;
????? printf("%d",f[n-1][i]);
????? for(j=i-1;j>=0;j--)printf("%08d",f[n-1][j]);
????? printf("\n");
??? }
??? return 0;
}?
?
?
?
?
?
?
1009:Counting Triangles
Problem Description
Given an equilateral triangle with n the length of its side, program to count how many triangles in it.
?
Input
The length n (n <= 500) of the equilateral triangle's side, one per line.
process to the end of the file
Output
The number of triangles in the equilateral triangle, one per line.
Sample Input
1
2
3
Sample Output
1
5
13
Author
JIANG, Jiefeng
Source
ZOJ Monthly, June 2003
?
?
題目分析:
?
題目大意:
邊長為n的等邊三角形由若干個邊長為1的等邊三角形組成,問它里面包含多少個等邊三角形(邊長從1到n,且有正立和倒立兩種情況)。
?
我的思路:
先分析幾個邊長小的等邊三角形的情況,借此得出遞推公式。
由于邊長>1的倒三角形比較難算,故分開討論
邊長???????????? ?????? 正三角形??????????? ?????? 邊長為1的倒三角????????? 邊長>1的倒三角形
1?????????????????? ?????? h(1)=1??????????????????????? g(1)=0????????????????????????????????????? 0
2?????????????????? ?????? h(2)=h(1)+3??????????????? g(2)=g(1)+1????????????????????????????? 0
3?????????????????? ?????? h(3)=h(2)+6??????????????? g(3)=g(2)+2????????????????????????????? 0
……
n?????????????????? h(n)=h(n-1)+ n*(n+1)/2???? g(n)=g(n-1)+n-1?????????????????????? ?
?
現在討論邊長>1的倒三角形數:
顯然當邊長>=4時才有邊長>1的倒三角形。
邊長????? 底邊等分點數????????????????? 邊長為i(i>1)的倒三角形數量
4??????????? 4-1???????????????????????????????????? u(4)=(4-1)-2*(2-1)
5??????????? 5-1???????????????????????????????????? u(5)=u(4)+ (5-1)-2*(2-1)+ (5-1)-2*(3-1)
6??????????? 6-1???????????????????????????????????? u(6)=u(5)+ [(6-1)-2*(2-1)]+ [(6-1)-2*(3-1)]
……
n??????????? n-1???????? u(n)=u(n-1)+[(n-1)-2*(2-1)]+[(n-1)-2*(3-1)]+…+[(n-1)-2*(i-1)]+…
?
于是得遞推關系:
當n<4時,f(n)=f(n-1)+n*(n+1)/2+(n-1);
當n>=4時,f(n)=f(n-1)+n*(n+1)/2+(n-1)+u(n);
初始條件為: f(1)=1;
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
?????? int n,i,j;
?????? __int64 f;
?????? while(scanf("%d",&n)!=EOF)
?????? {
?????? ? for(i=1;i<=n;i++)
????????????? if(i==1)f=1;
????????????? else
????????????? {
????????????? ? f+=i*(i+1)/2+(i-1);??????? //加上正立三角形數和邊長為1的倒三角形數
????????????? ? if(i>=4)
????????????? ??? for(j=3;i-j>=1;j+=2)f+=i-j;????? //當n>=4時,加上邊長>1的倒三角形數
????????????? ? }
?????? ? printf("%I64d\n",f);
?????? }
?????? return 0;
}?
?
?
?
?
?
1010:Tiling a Grid With Dominoes
Problem Description
We wish to tile a grid 4 units high and N units long with rectangles (dominoes) 2 units by one unit (in either orientation). For example, the figure shows the five different ways that a grid 4 units high and 2 units wide may be tiled.
Write a program that takes as input the width, W, of the grid and outputs the number of different ways to tile a 4-by-W grid.
Input
The first line of input contains a single integer N, (1 ≤ N ≤ 1000) which is the number of datasets that follow.
Each dataset contains a single decimal integer, the width, W, of the grid for this problem instance.
Output
For each problem instance, there is one line of output: The problem instance number as a decimal integer (start counting at one), a single space and the number of tilings of a 4-by-W grid. The values of W will be chosen so the count will fit in a 32-bit integer.
Sample Input
3
2
3
7
Sample Output
1 5
2 11
3 781
Source
2008 "Shun Yu Cup" Zhejiang Collegiate Programming Contest - Warm Up(1)
?
?
題目分析:
?
題目大意:
用1×2的多米諾骨牌,拼成4×w的矩形,總共有多少種方法?
?
我的思路:
此題與1002類似,但此題比1002復雜得多,用遞歸己經不能解決問題了,但可以借鑒它的思想,再轉用數組存儲即可。先說一下它的思想:
設f(a,b,c,d)表示第一行覆蓋a格,第二行覆蓋b格,第三行覆蓋c格,第四行覆蓋d格時的方法數,當拼成4*w的矩形時,有f(w,w,w,w)種方法。那么在此之前,它有哪些狀態呢?由于骨排要么是橫放要么是豎放,所以在取走第w列時,有下面幾種情況:(a=b=c=d=w)
(1)f(a-1,b-1,c-2,d-2);//第一行第二行是豎放的,另外兩行是橫放的,其他情況類似
(2)f(a-2,b-2,c-1,d-1);
(3)f(a-2,b-1,c-1,d-2);
(4)f(a-2,b-2,c-2,d-2);
(5)f(a-1,b-1,c-1,d-1);
現在又要考慮上面的情況又是怎么得來的:
對于(1),它是由f(a-2,b-2,c,d)和f(a-1,b-1,c,d)得來的;
對于(2),它是由f(a,b,c-1,d-1)和f(a,b,c-2,d-2)得來的;
對于(3),它是由f(a,b-2,c-2,d)和f(a,b-1,c-1,d)得來的;
對于(4)和(5),它跟a=b=c=d的情況一樣;
另外,還有一種情況:當a=d且b=c且a>b時,它是由f(a-2,b,c,d-2)得來的。
下一步就要確定初始條件:
當a=b=c=d<0時,f(a,b,c,d)=0;
當a=b=c=d=0或者1時,f(a,b,c,d)=1;
當a=b=0且c=d=1或者a=b=1且c=d=0時,f(a,b,c,d)=1;
當a=d=0且b=c=1時,f(a,b,c,d)=1;
當a=d=1且b=c=1時,f(a,b,c,d)=0;
剛才已經說過,用遞歸會超時,所以要轉成數組來存儲,下面是數組的轉化:
以1表示己經覆蓋,0表示未覆蓋,故每列均可由一個二進制數表示,情況如下:
f[t][0]:0000
f[t][1]:0011
f[t][2]:0110
f[t][3]:1001
f[t][4]:1100
f[t][5]:1111
初始條件和狀態轉換均可參考上面的思想。
?
?
以下是我的代碼:
?
#include<stdio.h>
#define c 25
int main()
{
??? int n,w,t;
??? int f[c+1][7];
??? f[1][0]=f[1][1]=f[1][2]=f[1][4]=f[1][5]=1;
??? f[1][3]=0;
??? for(t=2;t<=c;t++)
??? {
???? f[t][0]=f[t-1][5];
???? f[t][1]=f[t-1][5]+f[t-1][4];
???? f[t][2]=f[t-1][5]+f[t-1][3];
???? f[t][3]=f[t-1][2];
???? f[t][4]=f[t-1][5]+f[t-1][1];
???? f[t][5]=f[t-1][0]+f[t-1][1]+f[t-1][2]+f[t-1][4]+f[t-1][5];????
? ???}
??? while(scanf("%d",&n)!=EOF)
??? {
????? int i=1;
????? while(n--)
????? {
??????? scanf("%d",&w);
??????? printf("%d %d\n",i++,f[w][5]);
????? }
??? }
??? return 0;
}?
?
?
?
由于時間有限,只分析以上10道題,以下10道題粘代碼
?
1011:漢諾塔V
Problem Description
用1,2,...,n表示n個盤子,稱為1號盤,2號盤,...。號數大盤子就大。經典的漢諾塔問
題經常作為一個遞歸的經典例題存在。可能有人并不知道漢諾塔問題的典故。漢諾塔來源于
印度傳說的一個故事,上帝創造世界時作了三根金剛石柱子,在一根柱子上從下往上按大小
順序摞著64片黃金圓盤。上帝命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱
子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一回只能移動一個圓盤。我們
知道最少需要移動2^64-1次.在移動過程中發現,有的圓盤移動次數多,有的少 。 告之盤
子總數和盤號,計算該盤子的移動次數.
Input
包含多組數據,首先輸入T,表示有T組數據.每個數據一行,是盤子的數目N(1<=N<=60)和盤
號k(1<=k<=N)。
Output
對于每組數據,輸出一個數,到達目標時k號盤需要的最少移動數。
Sample Input
2
60 1
3 1
Sample Output
576460752303423488
4
?
Author
Zhousc@ECJTU
Source
ECJTU 2008 Spring Contest
?
我的代碼如下:
?
#include<stdio.h>
#include<math.h>
int main()
{
??? int t,n,k;
??? __int64 f;
??? while(scanf("%d",&t)!=EOF)
??? while(t--)
??? {
?????? scanf("%d%d",&n,&k);
?????? f=(__int64)pow(2,n-k);
?????? printf("%I64d\n",f);
??? }
??? return 0;
}?
?
1012:漢諾塔VI
Problem Description
n個盤子的漢諾塔問題的最少移動次數是2^n-1,即在移動過程中會產生2^n個系列。由于
發生錯移產生的系列就增加了,這種錯誤是放錯了柱子,并不會把大盤放到小盤上,即各柱
子從下往上的大小仍保持如下關系 :
n=m+p+q
a1>a2>...>am
b1>b2>...>bp
c1>c2>...>cq
計算所有會產生的系列總數.
Input
包含多組數據,首先輸入T,表示有T組數據.每個數據一行,是盤子的數
目N<30.
Output
對于每組數據,輸出移動過程中所有會產生的系列總數。
Sample Input
3
1
3
29
Sample Output
3
27
68630377364883
Author
Zhousc@ECJTU
Source
ECJTU 2008 Spring Contest
?
?
以下是我的代碼:
?
#include<stdio.h>
#include<math.h>
int main()
{
??? double f;
??? int t,n;
??? while(scanf("%d",&t)!=EOF)
??? while(t--)
??? {
????? scanf("%d",&n);
????? f=pow(3,n);
????? printf("%.0lf\n",f);
??? }
??? return 0;
}?
?
1013:蟠桃記
Problem Description
喜歡西游記的同學肯定都知道悟空偷吃蟠桃的故事,你們一定都覺得這猴子太鬧騰了,其實你們是有所不知:悟空是在研究一個數學問題!
什么問題?他研究的問題是蟠桃一共有多少個!
不過,到最后,他還是沒能解決這個難題,呵呵^-^
當時的情況是這樣的:
第一天悟空吃掉桃子總數一半多一個,第二天又將剩下的桃子吃掉一半多一個,以后每天吃掉前一天剩下的一半多一個,到第n天準備吃的時候只剩下一個桃子。聰明的你,請幫悟空算一下,他第一天開始吃的時候桃子一共有多少個呢?
Input
輸入數據有多組,每組占一行,包含一個正整數n(1<30>
Output
對于每組輸入數據,輸出第一天開始吃的時候桃子的總數,每個測試實例占一行。
Sample Input
2
4
Sample Output
4
22
Author
lcy
Source
C語言程序設計練習(二)
?
?
#include<stdio.h>
int main()
{
?????? int f,n;
?????? while(scanf("%d",&n)!=EOF)
?????? {
????????????? f=1;
????????????? while(n!=1)f=2*(f+1),n--;
????????????? printf("%d\n",f);
?????? }
?????? return 0;
}?
?
1014:超級樓梯
Problem Description
有一樓梯共M級,剛開始時你在第一級,若每次只能跨上一級或二級,要走上第M級,共有多少種走法?
Input
輸入數據首先包含一個整數N,表示測試實例的個數,然后是N行數據,每行包含一個整數M(1<=M<=40),表示樓梯的級數。
Output
對于每個測試實例,請輸出不同走法的數量
Sample Input
2
2
3
Sample Output
1
2
Author
lcy
Source
2005實驗班短學期考試
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
?????? int s[41],n,m,i;
?????? while(scanf("%d",&n)!=EOF)
?????? while(n--)
?????? {
????????????? scanf("%d",&m);
????????????? for(i=0;i<m;i++)
????????????? {
????????????? ?if((i==0)||(i==1))s[i]=1;
?????? ????? else if(i>1)s[i]=s[i-1]+s[i-2];
????????????? }
????????????? printf("%d\n",s[m-1]);
?????? }
?????? return 0;
}?
?
?
1015:一只小蜜蜂...
Problem Description
有一只經過訓練的蜜蜂只能爬向右側相鄰的蜂房,不能反向爬行。請編程計算蜜蜂從蜂房a爬到蜂房b的可能路線數。
其中,蜂房的結構如下所示。
Input
輸入數據的第一行是一個整數N,表示測試實例的個數,然后是N 行數據,每行包含兩個整數a和b(0<50>
Output
對于每個測試實例,請輸出蜜蜂從蜂房a爬到蜂房b的可能路線數,每個實例的輸出占一行。
Sample Input
2
1 2
3 6
Sample Output
1
3
Author
lcy
Source
遞推求解專題練習(For Beginner)
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
?????? int s[41],n,m,i;
?????? while(scanf("%d",&n)!=EOF)
?????? while(n--)
?????? {
????????????? scanf("%d",&m);
????????????? for(i=0;i<m;i++)
????????????? {
????????????? ?if((i==0)||(i==1))s[i]=1;
?????? ????? else if(i>1)s[i]=s[i-1]+s[i-2];
????????????? }
????????????? printf("%d\n",s[m-1]);
?????? }
?????? return 0;
}?
?
?
?
1016:不容易系列之(3)—— LELE的RPG難題
Problem Description
人稱“AC女之殺手”的超級偶像LELE最近忽然玩起了深沉,這可急壞了眾多“Cole”(LELE的粉絲,即"可樂"),經過多方打探,某資深Cole終于知道了原因,原來,LELE最近研究起了著名的RPG難題:
有排成一行的n個方格,用紅(Red)、粉(Pink)、綠(Green)三色涂每個格子,每格涂一色,要求任何相鄰的方格不能同色,且首尾兩格也不同色.求全部的滿足要求的涂法.
以上就是著名的RPG難題.
如果你是Cole,我想你一定會想盡辦法幫助LELE解決這個問題的;如果不是,看在眾多漂亮的痛不欲生的Cole女的面子上,你也不會袖手旁觀吧?
Input
輸入數據包含多個測試實例,每個測試實例占一行,由一個整數N組成,(0<=50)。< P>
Output
對于每個測試實例,請輸出全部的滿足要求的涂法,每個實例的輸出占一行。
Sample Input
1
2
Sample Output
3
6
Author
lcy
Source
遞推求解專題練習(For Beginner)
?
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? int n,i;
??? __int64 f[51];
?? ?while(scanf("%d",&n)!=EOF)
??? {
????? for(i=0;i<n;i++)
??????? if(i==0)f[i]=3;
??????? else if((i==1)||(i==2))f[i]=6;
??????? else f[i]=f[i-1]+2*f[i-2];
????? printf("%I64d\n",f[n-1]);
??? }
??? return 0;
}?
?
?
?
1017:阿牛的EOF牛肉串
Problem Description
今年的ACM暑期集訓隊一共有18人,分為6支隊伍。其中有一個叫做EOF的隊伍,由04級的阿牛、XC以及05級的COY組成。在共同的集訓生活中,大家建立了深厚的友誼,阿牛準備做點什么來紀念這段激情燃燒的歲月,想了一想,阿牛從家里拿來了一塊上等的牛肉干,準備在上面刻下一個長度為n的只由"E" "O" "F"三種字符組成的字符串(可以只有其中一種或兩種字符,但絕對不能有其他字符),阿牛同時禁止在串中出現O相鄰的情況,他認為,"OO"看起來就像發怒的眼睛,效果不好。
你,NEW ACMer,EOF的崇拜者,能幫阿牛算一下一共有多少種滿足要求的不同的字符串嗎?
PS: 阿牛還有一個小秘密,就是準備把這個刻有 EOF的牛肉干,作為神秘禮物獻給杭電五十周年校慶,可以想象,當校長接過這塊牛肉干的時候該有多高興!這里,請允許我代表杭電的ACMer向阿牛表示感謝!
再次感謝!
Input
輸入數據包含多個測試實例,每個測試實例占一行,由一個整數n組成,(0<40>
Output
對于每個測試實例,請輸出全部的滿足要求的涂法,每個實例的輸出占一行。
Sample Input
1
2
Sample Output
3
8
Author
lcy
Source
遞推求解專題練習(For Beginner)
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? int n,i;
??? __int64 f[41];
??? while(scanf("%d",&n)!=EOF)
??? {
????? for(i=0;i<n;i++)
?????? if(i==0)f[i]=3;
?????? else if(i==1)f[i]=8;
?????? else f[i]=2*(f[i-1]+f[i-2]);
????? printf("%I64d\n",f[n-1]);
??? }
??? return 0;
}?
?
?
?
1018:折線分割平面
Problem Description
我們看到過很多直線分割平面的題目,今天的這個題目稍微有些變化,我們要求的是n條折線分割平面的最大數目。比如,一條折線可以將平面分成兩部分,兩條折線最多可以將平面分成7部分,具體如下所示。
Input
輸入數據的第一行是一個整數C,表示測試實例的個數,然后是C 行數據,每行包含一個整數n(0<=10000),表示折線的數量。< P>
Output
對于每個測試實例,請輸出平面的最大分割數,每個實例的輸出占一行。
Sample Input
2
1
2
Sample Output
2
7
Author
lcy
Source
遞推求解專題練習(For Beginner)
?
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? int c,n,i;
??? __int64 f;
??? while(scanf("%d",&c)!=EOF)
??? while(c--)
??? {
????? scanf("%d",&n);
????? for(i=1;i<=n;i++)
??????? if(i==1)f=2;
??????? else f+=4*i-3;
????? printf("%I64d\n",f);
??? }
??? return 0;
}?
?
?
1019:漢諾塔III
Problem Description
約19世紀末,在歐州的商店中出售一種智力玩具,在一塊銅板上有三根桿,最左邊的桿上自上而下、由小到大順序串著由64個圓盤構成的塔。目的是將最左邊桿上的盤全部移到右邊的桿上,條件是一次只能移動一個盤,且不允許大盤放在小盤的上面。
現在我們改變游戲的玩法,不允許直接從最左(右)邊移到最右(左)邊(每次移動一定是移到中間桿或從中間移出),也不允許大盤放到下盤的上面。
Daisy已經做過原來的漢諾塔問題和漢諾塔II,但碰到這個問題時,她想了很久都不能解決,現在請你幫助她。現在有N個圓盤,她至少多少次移動才能把這些圓盤從最左邊移到最右邊?
Input
包含多組數據,每次輸入一個N值(1<=N=35)。
Output
對于每組數據,輸出移動最小的次數。
Sample Input
1
3
12
Sample Output
2
26
531440
Author
Rabbit
Source
RPG專場練習賽
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? __int64 f[36];
??? int n,i;
??? while(scanf("%d",&n)!=EOF)
??? {
??????? if(n==1)f[n]=2;
??????? else for(i=2;i<=n;i++)f[i]=3*f[i-1]+2;
??????? printf("%I64d\n",f[n]);
??? }
??? return 0;
}?
?
?
1020:跳舞毯
Problem Description
由于長期缺乏運動,小黑發現自己的身材臃腫了許多,于是他想健身,更準確地說是減肥。
小黑買來一塊圓形的毯子,把它們分成三等分,分別標上A,B,C,稱之為“跳舞毯”,他的運動方式是每次都從A開始跳,每次都可以任意跳到其他塊,但最后必須跳回A,且不能原地跳.為達到減肥效果,小黑每天都會堅持跳n次,有天他突然想知道當他跳n次時共幾種跳法,結果想了好幾天沒想出來-_-
現在就請你幫幫他,算出總共有多少跳法。
Input
測試輸入包含若干測試用例。每個測試用例占一行,表示n的值(1<=n<=1000)。
當n為0時輸入結束。
Output
每個測試用例的輸出占一行,由于跳法非常多,輸出其對10000取模的結果.
Sample Input
2
3
4
0
Sample Output
2
2
6
Author
蔥頭
Source
2008信息工程學院集訓隊——選拔賽
?
?
以下是我的代碼:
?
#include<stdio.h>
int main()
{
??? int n,i;
??? __int64 f[1001];
??? __int64 g[1001];
??? while(scanf("%d",&n)!=EOF&&n!=0)
??? {
????? for(i=0;i<n;i++)
?????? if(i==0)f[i]=0,g[i]=1;
?????? else if(i==1)f[i]=2,g[i]=1;
?????? else
?????? {
???????? f[i]=2*g[i-1]%10000;
???????? g[i]=(f[i-1]+g[i-1])%10000;
???????? }
????? printf("%I64d\n",f[n-1]);
??? }
??? return 0;
}?
總結
以上是生活随笔為你收集整理的ACM训练赛--递推专题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU2085:核反应堆(递推)
- 下一篇: Xcode clang-omp open