問題 A: 遞歸求解 時間限制: 5 Sec 內存限制: 128 MB 提交: 6 解決: 2 201501010119 提交狀態討論版 題目描述 使用遞歸編寫一個程序,求如下數列的前n項: s=1−12 +13 −14 +15 −16 +....+1n s=1−12+13−14+15−16+....+1n 輸入 多組數據輸入,每組輸入一個正整數n 輸出 輸出前n項的結果(精確到小數點後六位) 樣例輸入 Copy 1 樣例輸出 Copy 1.000000
#include <bits/stdc++.h> using namespace std; double f(int n) { if(n==1) return 1; else if(n%2==0) { return f(n-1.0)-1.0/n; } else if(n%2!=0) { return f(n-1)+1.0/n; } } int main() { int n; while(scanf("%d",&n)!=EOF) { printf("%.6f\n",f(n)); } return 0; }
問題 D: 數的劃分 時間限制: 1 Sec 內存限制: 128 MB 提交: 0 解決: 0 201501010119 提交狀態討論版 題目描述 使用遞歸編寫一個程序,求一個正整數n的全部劃分個數。 例如,輸入3,輸出3;輸入4,輸出5。 輸入 多組輸入,每一組是一個正整數n。 輸出 輸出劃分數。 樣例輸入 Copy 3 4 樣例輸出 Copy 3 5
感受這個題和分蘋果有點相似(前面寫過);c++
f(3)=3,f(4)=5,f(6)=11;算法
題目意思:將一個正整數劃分爲幾個正整數;數組
3的分法:3;2+1;1+1+1函數
4的分法:4;2+2;1+3;1+2+1;1+1+1+1測試
6的分法:6;1+5;4+2;4+1+1;3+3;3+2+1;3+1+1+1;2+2+2;2+2+1+1;2+1+1+1+1;1+1+1+1+1+1spa
設n,m;將n分解成不大於m的數設爲:f(n,m),意思是:舉個栗子,f(6,3),將6分紅不大於3的數的分法,這樣分:3,3; 3,2,1; 3,1,1,1;.net
這樣看來,f(6,3)的分法能夠由n-m的數(稱爲剩下的數)有幾種分法;設計
因此f(6,3)由兩種分法組成,第一種是f(3,3)組成(被減掉的最大數),第二種是被減掉剩下的數的劃分方法,也就是f(6,2);code
這個就是咱們的通常規律;blog
如今來討論特殊狀況:
f(n,1)=1,n>=1; 將n分解成n個1,只有一種分法;
f(n,m),n<m, 其實就等於f(n,n); 因此f(1,m)=1;
f(n,n)=f(n,n-1)+1(本身等於本身的狀況,舉個栗子:6分紅6); f(n,n-1)又能夠遞歸到f(n,m)的通常狀況;
#include <bits/stdc++.h> using namespace std; int q(int n,int m) { if((n<1)||(m<1)) { return 0; } if((n==1)||(m==1)) { return 1; } if(n<m) return q(n,n); if(n==m) return q(n,m-1)+1; else return q(n,m-1)+q(n-m,m); } int main() { int n; while(cin>>n) { q(n,n); //輸入狀況是這樣子 cout<<q(n,n)<<endl; } return 0; }
感受這題的難點就是要想到如何分解整數,按照哪幾個條件來分;
大概遞歸樹就是這樣子的吧~
問題 E: 漢諾塔 時間限制: 1 Sec 內存限制: 128 MB 提交: 0 解決: 0 201501010119 提交狀態討論版 題目描述 使用遞歸編寫一個程序實現漢諾塔問題,要求在輸入圓盤數量以後,輸出圓盤的移動步驟,輸出格式示例以下: 第1步:1號盤從A柱移至B柱 第2步:2號盤從A柱移至C柱 輸入 多組測試用例,每組輸入一個正整數n,n表明圓盤數量。 輸出 每組輸出之間有一行空行。 樣例輸入 Copy 3 樣例輸出 Copy 第1步:1號盤從A柱移至C柱 第2步:2號盤從A柱移至B柱 第3步:1號盤從C柱移至B柱 第4步:3號盤從A柱移至C柱 第5步:1號盤從B柱移至A柱 第6步:2號盤從B柱移至C柱 第7步:1號盤從A柱移至C柱
#include <bits/stdc++.h> using namespace std; int s=0; void move(int n,char a,char b) { printf("第%d步:%d號盤從%c柱移至%c柱\n",++s,n,a,b); } void hano(int n,char a,char b,char c) //從a移到c藉助b { if(n==1) { move(1,a,c); } else { hano(n-1,a,c,b); move(n,a,c); hano(n-1,b,a,c); } } int main() { int n; while(scanf("%d",&n)!=EOF) { s=0; hano(n,'A','B','C'); //注意ABC要打單引號 cout<<endl; } return 0; }
本題我的感受難點是存總步數(第幾步第幾步...)
因此用一個全局變量來存,並在每次輸入的時候從新歸零;
詳細請參考前面的博客漢諾塔
問題 B: 字母全排列 時間限制: 1 Sec 內存限制: 128 MB 提交: 2 解決: 1 201501010119 提交狀態討論版 題目描述 編寫一個程序,使用遞歸算法輸出一個一維字符數組中全部字符的全排列,假設字符都不同。例如{'a','b','c'}的全排列爲(a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a) 輸入 多組測試用例,每組輸入一個正整數n(0<n<=26)。 輸出 輸出從a開始,連續n個字母的全排列,且每組輸出之間用空格隔開。 樣例輸入 Copy 1 2 樣例輸出 Copy a ab ba
#include<bits/stdc++.h> using namespace std; void swap(char a[],int i,int j) //交換函數 { int t=a[i]; a[i]=a[j]; a[j]=t; }
void f(char a[],int k,int n) { if(k>=n) //只剩下一個元素 { for(int i=0;i<n;i++) printf("%c",a[i]); cout<<endl; } else { for(int i=k;i<n;i++) //循環用來判斷每次排列誰作第一個,遞歸用來遞歸到下一個元素的判斷 { swap(a,k,i); //還原 f(a,k+1,n); swap(a,k,i); //還原 } } } int main() { int n; while(cin>>n) { char a[27]; int i; int s=97; for(i=0;i<n;i++) //把須要的字母按順序存進數組a { a[i]=s; s++; } f(a,0,n); cout<<endl; } return 0; }
這個題和書上的數字全排列問題相似(劃掉);
全排列問題的核心思想是:各個排列數輪流作第一個;
分兩步:n=1,只有一個元素;n>1,一直遞歸到只剩下一個元素;
注意點:輪流作完了第一個後要還原!還原有兩步!
問題 F: 幸運人士 時間限制: 1 Sec 內存限制: 128 MB 提交: 1 解決: 1 201501010119 提交狀態討論版 題目描述 一次大型派對的最後節目是選出一位幸運人士,該人士將得到派對組織者準備的一個鑽石戒指。 而選擇幸運人士的辦法是讓全部人員一字排列,而後從左至右點數,凡是奇數號的所有剔除。 對於剩下的人員,又從左至右點數,逢奇數號就剔除。 如此不斷遞歸下去,直到只剩下一我的爲止,此人即爲幸運之人。 請設計一個遞歸算法計算幸運之人所在的位置。 輸入 多組數據,每組輸入一個正整數n。 輸出 輸出最後剩下的那我的的位置。 樣例輸入 Copy 1 2 3 樣例輸出 Copy 1 2 2
#include <bits/stdc++.h> using namespace std; int f(int a,int b) { if(a>1) { if(a%2==0) { b++; return f(a/2,b); } if(a%2!=0) { b++; return f(a/2,b); } } if(a==1) return b; } int main() { int n; while(cin>>n) { int s,i,c; c=1; s=f(n,0); for(i=0;i<s;i++) c=c*2; cout<<c<<endl; } return 0; }
算。。。水題?找規律?以前一直覺得用數組,後來室友發現了規律
問題 C: 九數組分數 時間限制: 1 Sec 內存限制: 128 MB 提交: 0 解決: 0 201501010119 提交狀態討論版 題目描述 1, 2, 3...9 這九個數字組成一個分數,其值剛好爲1/3,要求每一個數字出現且只能出現一次,如何組合?編寫程序輸出全部的組合。 輸入 無 輸出 輸出全部的結果,若是有多個,每條結果佔一行。 結果的格式 : xxxx/xxxxx ,按照分子從小到大的順序輸出。
#include<bits/stdc++.h> using namespace std; int arr[2]; int k=0; void f(int aa[],int m,int n) { if(m==n) { int a,b; a=aa[3]*1000+aa[2]*100+aa[1]*10+aa[0]; b=aa[8]*10000+aa[7]*1000+aa[6]*100+aa[5]*10+aa[4]; if(a*3==b) arr[k++]=a; } else { int i; for(i=m;i<=n;i++) { swap(aa[m],aa[i]); f(aa,m+1,n); swap(aa[m],aa[i]); } } } int main() { int aa[]={1,2,3,4,5,6,7,8,9}; f(aa,0,8); sort(arr,arr+2); for(int j=0;j<2;j++) printf("%d/%d\n",arr[j],arr[j]*3); return 0; }
和全排列相似;
判斷比值剛好爲三分之一,將除法轉換爲乘法來算
問題 H: 漢諾塔-3 時間限制: 1 Sec 內存限制: 32 MB 提交: 1 解決: 1 201501010119 提交狀態討論版 題目描述 用1,2,...,n表示n個盤子,稱爲1號盤,2號盤,...。號數大盤子就大。經典的漢諾塔問題常常做爲一個遞歸的經典例題存在。可能有人並不知道漢諾塔問題的典故。漢諾塔來源於印度傳說的一個故事,上帝創造世界時做了三根金剛石柱子,在一根柱子上從下往上按大小順序摞着64片黃金圓盤。上帝命令婆羅門把圓盤從下面開始按大小順序從新擺放在另外一根柱子上。而且規定,在小圓盤上不能放大圓盤,在三根柱子之間一回只能移動一個圓盤。咱們知道最少須要移動2^64-1次.在移動過程當中發現,有的圓盤移動次數多,有的少 。 告之盤子總數和盤號,計算該盤子的移動次數. 輸入 包含多組數據,首先輸入T,表示有T組數據.每一個數據一行,是盤子的數目N(1<=N<=60)和盤號k(1<=k<=N)。 輸出 對於每組數據,輸出一個數,到達目標時k號盤須要的最少移動數。 樣例輸入 Copy 2 60 1 3 1 樣例輸出 Copy 576460752303423488 4
#include<bits/stdc++.h> using namespace std; int main() { int t,n,k; cin>>t; while(t--) { cin>>n>>k; int long long s,a; int i; s=1; a=n-k; for(i=0;i<a;i++) { s=s*2; } cout<<s<<endl; } return 0; }
這個也算找規律?
貼一個別人總結的漢諾塔問題