日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

递归算法思路以及题目总结(未完待续...)

發(fā)布時(shí)間:2025/3/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 递归算法思路以及题目总结(未完待续...) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2018-3-10

之前在一個(gè)網(wǎng)站上看到了一些遞歸題目的合集,題目來(lái)源是:
http://bailian.openjudge.cn/,
是北京大學(xué)ACM訓(xùn)練和相關(guān)程序課程在線考試系統(tǒng)。
我先列出所有的題目編號(hào),具體代碼會(huì)在下面:

題目名稱(chēng)/題目ID 菲波那契數(shù)列 2753 二叉樹(shù) 2756 逆波蘭表達(dá)式 2694 放蘋(píng)果 1664 紅與黑 2816 八皇后問(wèn)題 2754 木棍問(wèn)題 2817 城堡 2815 分解因數(shù) 2749 迷宮 279024 2787 文件結(jié)構(gòu)"圖" 2775 小游戲 2802 碎紙機(jī) 2803 棋盤(pán)分割 1191 棋盤(pán)問(wèn)題 1321

1.斐波那契數(shù)列
這個(gè)對(duì)我們來(lái)說(shuō)應(yīng)該并不陌生,f(n)=f(n-1)+f(n-2),初始化f(1)=1,f(2)=1,當(dāng)n比較大的時(shí)候,我們會(huì)發(fā)現(xiàn)有些f(m)會(huì)被我們計(jì)算了多次,那么我們可以先將它們存到數(shù)組里,如果我們需要用的話直接去數(shù)組里面取就可以了。

#include<iostream> #include<cstring> using namespace std;const int N = 20; int fib[N+1];int dfs(int p){if (fib[p]) return fib[p];fib[p]=dfs(p-1)+dfs(p-2);return fib[p]; }int main(){memset(fib,0,sizeof(fib));fib[1]=1;fib[2]=1;int t,n;cin>>t;while(t--){cin>>n;if (fib[n]) cout<<fib[n]<<endl;else cout<<dfs(n)<<endl;}return 0; }

2.二叉樹(shù)
這個(gè)題目讓我們找到兩個(gè)節(jié)點(diǎn)的最大公共節(jié)點(diǎn),我們不難發(fā)現(xiàn)二叉樹(shù)的性質(zhì),父節(jié)點(diǎn)的值是子節(jié)點(diǎn)值的1/2,利用這個(gè)特點(diǎn)我們可以一步步的向上找。

#include<iostream> using namespace std;int x,y;int dfs(int i,int j){if (i==j) return i;if (i>j){return dfs(i/2,j);}else{return dfs(i,j/2);} }int main(){while (cin>>x>>y){cout<<dfs(x,y)<<endl;}return 0; }

3.逆波蘭表達(dá)式
說(shuō)實(shí)話,我覺(jué)得這個(gè)題目本身就很神奇,我在想這個(gè)題目的時(shí)候在糾結(jié)輸入到底應(yīng)該如何處理,后來(lái)在小伙伴的提醒之下寫(xiě)出了答案。
我們可以在函數(shù)里面等待輸入,當(dāng)輸入的是運(yùn)算符的時(shí)候,我會(huì)等待輸入兩個(gè)數(shù)字來(lái)進(jìn)行運(yùn)算,如果輸入的還是運(yùn)算符,我們可以繼續(xù)等待,直至輸入數(shù)字,返回結(jié)果與相應(yīng)的運(yùn)算符進(jìn)行運(yùn)算。

#include<iostream> #include<cstring> #include<cmath> #include<cstdio> using namespace std;char x[10];double dfs(){cin>>x;switch(x[0]){case '+':{return dfs()+dfs();break;}case '-':{return dfs()-dfs();break;}case '*':{return dfs()*dfs();break;}case '/':{return dfs()/dfs();break;}default:return atof(x);} }int main(){printf ("%f\n",dfs());return 0; }

4.放蘋(píng)果
這道題目老早就見(jiàn)過(guò),但是在這一次寫(xiě)的時(shí)候又出現(xiàn)了 一個(gè)問(wèn)題,我知道如果第n個(gè)盤(pán)子不用的話就等同于m個(gè)蘋(píng)果放在n-1個(gè)盤(pán)子中,但是如果我們第n個(gè)盤(pán)子用了呢?那我們就得把所有的n個(gè)盤(pán)子里面都放一個(gè)才可以,因?yàn)槲覀冞@個(gè)是不考慮順序的,我們必須保證得到的兩個(gè)是完全沒(méi)有交集的,我們不能把相同的情況計(jì)算多遍!如果說(shuō)我們沒(méi)有把n個(gè)盤(pán)子都放一個(gè)的話,那么我們?cè)趂(m,n-1)里面也會(huì)出現(xiàn)空的盤(pán)子,那可能就出現(xiàn)重復(fù)的情況了。

#include<iostream> using namespace std;int dfs(int m,int n){if (m<0||n<0){return 0;}if (m==1||n==1||m==0||n==0) return 1;return dfs(m,n-1)+dfs(m-n,n); }int main(){int t;cin>>t;while (t--){int m,n;cin>>m>>n;cout<<dfs(m,n)<<endl;}return 0; }

5.紅與黑
這種題目應(yīng)該屢見(jiàn)不鮮了,就是走迷宮類(lèi)的題目,實(shí)現(xiàn)起來(lái)的套路似乎差不多。

#include<iostream> #include<cstring> using namespace std;const int N = 20; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; char x[N+1][N+1]; int res;void dfs(int p,int q){for (int k=0;k<4;k++){int ii=p+dx[k],jj=q+dy[k];if (x[ii][jj]=='.'){x[ii][jj]='#';res++;dfs(ii,jj);}} }int main(){int p,q,w,h;while (cin>>w>>h){if (w==0&&h==0){break;}memset(x,0,sizeof(x));res=0;for (int i=1;i<=h;i++){for (int j=1;j<=w;j++){cin>>x[i][j];if (x[i][j]=='@'){p=i;q=j;}}}dfs(p,q);cout<<res+1<<endl;}return 0; }

6.八皇后問(wèn)題
n皇后問(wèn)題之前在藍(lán)橋杯集訓(xùn)的時(shí)候有位學(xué)長(zhǎng)給我們講過(guò),有一種聽(tīng)過(guò)了就再也忘不了的感覺(jué)。。。

#include<iostream> #include<cstring> using namespace std;const int N = 8; bool h[N+1],z[2*N+1],y[2*N+1]; int r[N+1]; int res,n; bool flag;bool isvalid(int i,int j){if (h[j]||z[i-j+N]||y[i+j]) return false;return true; }void dfs(int step){if (flag) return ;if (step==N+1){res++;if (res==n){for (int i=1;i<=N;i++){cout<<r[i];}cout<<endl;flag=true;}return ; }for (int j=1;j<=N;j++){if (isvalid(step,j)){h[j]=true;z[step-j+N]=true;y[j+step]=true;r[step]=j;dfs(step+1);h[j]=false;z[step-j+N]=false;y[j+step]=false;}} }int main(){int t;cin>>t;while (t--){cin>>n;res=0;flag=false;memset(h,false,sizeof(h));memset(z,false,sizeof(z));memset(y,false,sizeof(y));dfs(1);}return 0; }

7.木棍問(wèn)題
說(shuō)一下我思路的轉(zhuǎn)變?!
首先我們得知道可能的答案的范圍,應(yīng)該是木棒的最大長(zhǎng)度max與木棒長(zhǎng)度之和sum之間,我們需要對(duì)這之間的值進(jìn)行枚舉直到找到滿足條件的即可。
對(duì)于某一個(gè)特定的長(zhǎng)度p,q=sum/p即為根數(shù),我們需要求出給定的木棒能不能組合成q根長(zhǎng)度為p的木棒即可。
我一開(kāi)始覺(jué)得只要像八皇后那樣即可,看能不能找到q個(gè)和為p的木棒即可,后來(lái)我發(fā)現(xiàn),這是不可行的,因?yàn)槲覀冊(cè)诨厮莸臅r(shí)候只有在當(dāng)前循環(huán)都不滿足條件(或者都計(jì)算過(guò)了)才會(huì)返回至上一層,那么我們必然會(huì)使用之前已經(jīng)有過(guò)的木棒了,這當(dāng)然是不可行的,比如說(shuō)1,2,3,4,8,8,8…,當(dāng)我們的p為11,q為3時(shí),我們到1,2,8時(shí)是滿足s=p=11的,然后我們就來(lái)到了第二個(gè)8,也滿足,然后來(lái)到了第三個(gè)8也滿足,我們會(huì)發(fā)現(xiàn)這里的1,2,被我們使用了多次,這當(dāng)然是不可行的。那我們肯定會(huì)想我們把當(dāng)前使用到的都存起來(lái),然后在滿足s=p=11時(shí)對(duì)這些值進(jìn)行標(biāo)記,以后不能再使用了,如果還是用當(dāng)前的這個(gè)方法當(dāng)然是不可行的,因?yàn)椴浑y發(fā)現(xiàn)即使我們對(duì)它們進(jìn)行了標(biāo)記也晚了。不僅要解決上面的問(wèn)題,就算我們對(duì)它們進(jìn)行了標(biāo)記,我們標(biāo)記的那些也可能再次失去標(biāo)記,比如說(shuō)我們只是求得了s=p的一個(gè)情況,剩下的也不一定可以滿足條件,反之,我們可以再換一種組合方式才可以使剩下的滿足條件,這需要我們?cè)僖淮芜M(jìn)行回溯,大概應(yīng)該就是這么個(gè)意思吧!

1.以一個(gè)小棒為開(kāi)頭,用dfs看看能否把這個(gè)小棒拼湊成p長(zhǎng),如果可以,用f[i]記錄下用過(guò)的小棒,然后繼續(xù)以另外一個(gè)小棒為開(kāi)頭,以此類(lèi)推。2.小棒的長(zhǎng)度從大到小排序。3.如果當(dāng)前最長(zhǎng)的小棒不能拼成p長(zhǎng),那么就返回前一步,更改前一步的最長(zhǎng)小棒的組合情況(這里不能是全部退出),不用再繼續(xù)搜索下去了。 #include<iostream> #include<algorithm> #include<cstring> using namespace std;const int N = 64; int n,x[N+1]; bool flag,f[N+1];bool cmp(int a,int b){return a>b; }bool dfs(int total,int unused,int left,int len){if (unused==0&&left==0) return true;if (left==0) left=len;for (int i=0;i<total;i++){if (f[i]) continue;if (x[i]>left) continue;f[i]=true;if (dfs(total,unused-1,left-x[i],len)){return true;}f[i]=false;if (x[i]==left||left==len) break;}return false; }int main(){while (cin>>n){if (n==0) break;int su=0;for (int i=0;i<n;i++){cin>>x[i];su+=x[i];}sort(x,x+n,cmp);for (int i=x[0];i<=su;i++){memset(f,false,sizeof(f));if (su%i!=0) continue;if (dfs(n,n,0,i)){cout<<i<<endl;break;}}}return 0; }

8.城堡
比較簡(jiǎn)單的一個(gè)題目,可以進(jìn)行處理的是:它給我們的是1,2,4,8分別對(duì)應(yīng)數(shù)二進(jìn)制表示的第0,1,2,3位,所以我們?cè)谂袛嗟臅r(shí)候只要作相應(yīng)的位運(yùn)算就可以判斷那個(gè)方向有沒(méi)有墻了。

#include<iostream> #include<cstring> using namespace std;const int N = 50; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; int num[4]={2,8,1,4}; int x[N+1][N+1]; bool f[N+1][N+1]; int sum,m,n;bool isvalid(int i,int j){if (i<1||j<1||i>m||j>n) return false;return true; }void dfs(int i,int j){for (int k=0;k<4;k++){int ii=i+dx[k],jj=j+dy[k];if (isvalid(ii,jj)&&(x[i][j]&num[k])==0&&!f[ii][jj]){f[ii][jj]=true;sum++;dfs(ii,jj);}} }int main(){while (cin>>m>>n){int res=0,num=0;memset(f,false,sizeof(f));for (int i=1;i<=m;i++){for (int j=1;j<=n;j++){cin>>x[i][j];}}for (int i=1;i<=m;i++){for (int j=1;j<=n;j++){if (!f[i][j]){f[i][j]=true;num+=1;sum=1;dfs(i,j);res=max(sum,res);}}}cout<<num<<endl<<res<<endl;}return 0; }

9.分解因數(shù)
如果說(shuō)某個(gè)數(shù)i能夠被n整除的話那么它就是n的一個(gè)因數(shù),然后我們只要再找到n=n/i的因數(shù)就可以了,這是一個(gè)遞歸的想法,由于題目要求1 < a1 <= a2 <= a3 <= … <= an,那么我們得記住當(dāng)前的ai,下一個(gè)ai+1必須滿足大于等于ai即可,當(dāng)然,遞歸結(jié)束的條件是n=1。

#include<iostream> using namespace std;int num;void dfs(int m,int n){if (n<=0) return ;if (n==1){num++;return ;}for (int i=m;i<=n;i++){if (n%i==0){dfs(i,n/i);}} }int main(){int t,n;cin>>t;while (t--){num=0;cin>>n;dfs(2,n);cout<<num<<endl;}return 0; }

10.迷宮
類(lèi)似的題目,唯一需要注意的是:如果起點(diǎn)或者終點(diǎn)有一個(gè)不能通行(為#),則看成無(wú)法辦到。

#include<iostream> using namespace std;const int N = 100; char x[N+1][N+1]; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; int n,ha,la,hb,lb; bool flag;bool isvalid(int i,int j){if (i<0||j<0||i>=n||j>=n) return false;return true; }void dfs(int i,int j){if (flag) return ;if (i==hb&&j==lb){flag=true;return ;}for (int k=0;k<4;k++){int ii=i+dx[k],jj=j+dy[k];if (isvalid(ii,jj)&&x[ii][jj]=='.'){x[ii][jj]='#';dfs(ii,jj);}} }int main(){int t;cin>>t;while (t--){flag=false;cin>>n;for (int i=0;i<n;i++){for (int j=0;j<n;j++){cin>>x[i][j];}}cin>>ha>>la>>hb>>lb;if (x[ha][la]=='#'||x[hb][lb]=='#'){cout<<"NO"<<endl;continue;}dfs(ha,la);if (flag) cout<<"YES"<<endl;else cout<<"NO"<<endl;}return 0; }

11.算24
說(shuō)實(shí)話,我覺(jué)得這個(gè)題目蠻好的。遞歸真的是個(gè)神奇的東西,我們不妨假設(shè)x[i]和x[j]是參加運(yùn)算的兩個(gè)數(shù),且我們假設(shè)i是小于j的,只要我們?cè)谶M(jìn)行x[i]-x[j]的時(shí)候同時(shí)也進(jìn)行一次x[j]-x[i]就可以了,我們將每次x[i]和x[j]操作后的值放在x[i]里面,那么我們每次進(jìn)行num-1的操作時(shí),需要將num-1對(duì)應(yīng)的值保存在x[j]里面,因?yàn)槲覀兠看蝘是從0到num-1進(jìn)行遍歷的,如果不保存的話我們將要失去它。當(dāng)然,我們還要進(jìn)行回溯來(lái)恢復(fù)x[i]和x[j]的值。

#include<iostream> #include<cmath> #define eps 1e-5 using namespace std;const int N = 4; double x[N+1];int dfs(int num){if (num==1){if (fabs(x[0]-24)<eps) return 1;return 0;}for (int i=0;i<num-1;i++){for (int j=i+1;j<num;j++){double p=x[i],q=x[j];x[j]=x[num-1];x[i]=p+q;if (dfs(num-1)) return 1;x[i]=p-q;if (dfs(num-1)) return 1;x[i]=q-p;if (dfs(num-1)) return 1;x[i]=p/q;if (dfs(num-1)) return 1;x[i]=q/p;if (dfs(num-1)) return 1;x[i]=p*q;if (dfs(num-1)) return 1;x[i]=p;x[j]=q;}}return 0; }int main(){while (cin>>x[0]>>x[1]>>x[2]>>x[3]){if (x[0]==0&&x[1]==0&&x[2]==0&&x[3]==0) break;if (dfs(4)){cout<<"YES"<<endl;}else{cout<<"NO"<<endl;}}return 0; }

12.棋盤(pán)問(wèn)題
先說(shuō)最后一個(gè)棋盤(pán)問(wèn)題,感覺(jué)這個(gè)像是八皇后題目的變形,其實(shí)思想都是差不多的,唯一需要我們注意的是,不是所有的地方都任由我們放置棋子了,當(dāng)然如果我們用列的視角來(lái)看這個(gè)題目的話,換言之就會(huì)存在某一列的任意位置都不能放置棋子的問(wèn)題了,所以說(shuō)如果我們輸入的k大于n的話是一定沒(méi)有滿足題意的解的,這時(shí)我們不能只用一個(gè)參數(shù)step來(lái)標(biāo)記當(dāng)前列了,我們需要兩個(gè)參數(shù),一個(gè)是當(dāng)前列,另一個(gè)是當(dāng)前放置的棋子的個(gè)數(shù),如果說(shuō)在l列有滿足條件的,那么我們就step+1,l+1,但是如果說(shuō)某一列不存在滿足條件的,那么我們就step不變,再去下一列尋找即可。

#include<iostream> #include<cstring> using namespace std;const int N = 8; char x[N+1][N+1]; bool h[N+1],flag; int n,k,sum,p;void dfs(int step,int l){if (step==k){sum++;return ;}if (l>n) return ;for (int i=1;i<=n;i++){if (!h[i]&&x[i][l]!='.'){h[i]=true;dfs(step+1,l+1);h[i]=false;}}dfs(step,l+1); }int main(){while (cin>>n>>k){if (n==-1&&k==-1){break;}memset(h,false,sizeof(h));for (int i=1;i<=n;i++){for (int j=1;j<=n;j++){cin>>x[i][j];}}if (k>n){cout<<0<<endl;continue;}sum=0;dfs(0,1);cout<<sum<<endl;}return 0; }

13.小游戲
在TLE了n多次之后還是沒(méi)有AC…
我覺(jué)得思路還是比較明確的,有三個(gè)值得我們注意的地方:

1)輸入里面是有空格的,而scanf在遇到空格時(shí)會(huì)結(jié)束輸入。 (2)我們求的次數(shù)等同于需要拐彎的次數(shù),而不是經(jīng)過(guò)的空白區(qū)域的個(gè)數(shù),所以我們需要兩個(gè)數(shù)來(lái)標(biāo)記當(dāng)前是從哪一個(gè)方向的格子過(guò)來(lái)的,但是我們經(jīng)過(guò)觀察可以發(fā)現(xiàn),只要用一個(gè)數(shù)(0~3)就能表示了。 (3)這個(gè)題目橫縱坐標(biāo)可能和我們平時(shí)的不太一樣(我是這么覺(jué)得的)。

雖然還是TLE,還是要附上代碼的。

#include<iostream> #include<cstdio> #include<cstring> using namespace std;const int N = 80; char x[N+1][N+1]; bool f[N+1][N+1]; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; int w,h,x1,y1,x2,y2,res;void dfs(int i,int j,int sum,int pp){if (sum>=res) return ;if (i==y2&&j==x2){if (sum<res) res=sum;return ;}for (int k=0;k<4;k++){int ii=i+dx[k],jj=j+dy[k];if (ii>=0&&jj>=0&&ii<=h+1&&jj<=w+1&&!f[ii][jj]&&x[ii][jj]!='X'){f[ii][jj]=true;if (pp==k){dfs(ii,jj,sum,k);}else{dfs(ii,jj,sum+1,k);}f[ii][jj]=false;}} }int main(){int n1=1;while (scanf ("%d%d",&w,&h)!=EOF){if (!w&&!h) break;for (int i=1;i<=h;i++){getchar();for (int j=1;j<=w;j++){x[i][j]=getchar();}}printf ("Board #%d:\n",n1++);int n2=1;while (scanf ("%d%d%d%d",&x1,&y1,&x2,&y2)!=EOF){if (!x1&&!y1&&!x2&&!y2) break;memset(f,false,sizeof(f));if (x[y1][x1]==' '||x[y2][x2]==' '){printf ("Pair %d: impossible.\n",n2++);continue;}res=10000;x[y2][x2]=' ';dfs(y1,x1,0,-1);x[y2][x2]='X';if (res==10000){printf ("Pair %d: impossible.\n",n2++);}else{printf ("Pair %d: %d segments.\n",n2++,res);}}printf ("\n");}return 0; }

14.碎紙機(jī)
大體的意思就是讓你把一串?dāng)?shù)字隨便分開(kāi)來(lái),給出能夠組成小于給定數(shù)字的最大的組合方式。
遞歸的回溯真是一個(gè)神奇的東西,首先我們要把給的那個(gè)數(shù)拆分開(kāi)來(lái)。如果每一位上的數(shù)字之和都大于給定的m的話,那么是無(wú)解的;如果說(shuō)對(duì)于某一個(gè)已經(jīng)求得的滿足條件的最大小于m的和,存在與他相等的,就把flag=true,也就是說(shuō)這是是大于一個(gè)滿足條件的,如果再存在比它大的滿足條件的,就把flag再置為false,因?yàn)槲覀兊闹狄呀?jīng)被更新過(guò)了。
我們得用一個(gè)數(shù)標(biāo)記我們來(lái)到了第幾個(gè)數(shù),當(dāng)來(lái)到最后一個(gè)數(shù)的時(shí)候我們就要進(jìn)行判斷了。

#include<iostream> #include<cstring> using namespace std;const int N = 6; int x[N+1],r[N+1],p[N+1]; int m,n,num,res_long,res_sum; bool flag;bool cut(int a){int sum=0;num=1;while (a){x[num++]=a%10;sum+=a%10;a/=10;}if (sum>m) return false;return true; }void dfs(int step,int sum_now,int k){if (sum_now>m) return ;if (step==0){if (sum_now>res_sum){memcpy(r,p,sizeof(p));res_long=k-1;res_sum=sum_now;flag=false;return;}if (sum_now==res_sum){flag=true;return ;}return ;}int tmp=0;for (int i=step;i>=1;i--){tmp=10*tmp+x[i];p[k]=tmp;dfs(i-1,sum_now+tmp,k+1);} }int main(){while (cin>>m>>n){if (m==0&&n==0) break;if (m==n){cout<<m<<" "<<m<<endl;continue;}if (!cut(n)){cout<<"error"<<endl;continue;}flag=false;res_long=0;res_sum=0;dfs(num-1,0,1);if (flag){cout<<"rejected"<<endl;}else{cout<<res_sum<<" ";for (int i=1;i<res_long;i++){cout<<r[i]<<" ";}cout<<r[res_long]<<endl;}}return 0; }

棋盤(pán)分割和文件結(jié)構(gòu)”圖” 這兩道題暫時(shí)還沒(méi)有解決…

總結(jié)

以上是生活随笔為你收集整理的递归算法思路以及题目总结(未完待续...)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。