赞
踩
目录
We all love recursion! Don't we?
Consider a three-parameter recursive function w(a, b, c):
if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns:
1
if a > 20 or b > 20 or c > 20, then w(a, b, c) returns:
w(20, 20, 20)
if a < b and b < c, then w(a, b, c) returns:
w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)
otherwise it returns:
w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)
This is an easy function to implement. The problem is, if implemented directly, for moderate values of a, b and c (for example, a = 15, b = 15, c = 15), the program takes hours to run because of the massive recursion.
Input
The input for your program will be a series of integer triples, one per line, until the end-of-file flag of -1 -1 -1. Using the above technique, you are to calculate w(a, b, c) efficiently and print the result.
Output
Print the value for w(a,b,c) for each triple.
Sample Input
- 1 1 1
- 2 2 2
- 10 4 6
- 50 50 50
- -1 7 18
- -1 -1 -1
Sample Output
- w(1, 1, 1) = 2
- w(2, 2, 2) = 4
- w(10, 4, 6) = 523
- w(50, 50, 50) = 1048576
- w(-1, 7, 18) = 1
思路:按照体中给出的递归方法,时间复杂度应该在o(3^n)到o(4^n)之间,但如果将每个节点的值保存下来时间复杂度就可以降到n^3,也就是所谓的记忆化搜索。
题中写法:
- #include<iostream>
- #include<algorithm>
- #include<set>
- #include<vector>
- #define ll long long
-
- using namespace std;
-
- int w(int a, int b, int c)
- {
- if(a <=0 || b <= 0 || c <= 0) return 1;
-
- if(a > 20 || b > 20 || c > 20) return w(20,20,20);
-
- if(a < b && b < c) return w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c);
-
- return w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
- }
-
- int main()
- {
- int a,b,c;
- while(cin>>a>>b>>c)
- {
- if(a == -1 && b == -1 && c == -1) break;
- printf("w(%d, %d, %d) = %d\n",a,b,c,w(a,b,c));
- }
- return 0;
- }

记忆化搜索写法:
- #include<iostream>
- #include<algorithm>
- #include<set>
- #include<vector>
- #define ll long long
-
- using namespace std;
-
- int dp[100][100][100];
-
- int w(int a, int b, int c)
- {
- if(a <=0 || b <= 0 || c <= 0) return 1;
-
- if(a > 20 || b > 20 || c > 20) return dp[a][b][c] = w(20,20,20);
-
- if(dp[a][b][c]) return dp[a][b][c];
-
- if(a < b && b < c) return dp[a][b][c] = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c);
-
- return dp[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
- }
-
- int main()
- {
- int a,b,c;
- while(cin>>a>>b>>c)
- {
- if(a == -1 && b == -1 && c == -1) break;
- printf("w(%d, %d, %d) = %d\n",a,b,c,w(a,b,c));
- }
- return 0;
- }

Glory非常喜欢玩滑滑梯游戏,下面给出了一个n,m的滑道,其中的数字表示滑道的高度。Glory可以从一个点出发向下滑行,每次只能滑行到相邻的位置(上下左右)中高度严格低于当前高度的地方,不能重复划行已经滑行过的地方,但他希望在这个滑道上滑行尽量远的距离,也即是找一条最长的滑道。
Input
第一行输入两个数n,m代表滑梯范围行n和列m(1 <= n,m <= 100)。下面是n行,每行有m个整数,代表高度h,(0<=h<=20000)
Output
输出一个值,代表Glory能够在滑滑梯上面滑行的最长长度是多少
Sample Input
3 3
9 1 2
5 6 7
8 4 3
Sample Output
4
Sample Input
4 7
7 6 5 4 3 2 1
1 5 1 1 1 1 1
1 4 3 1 1 1 1
1 5 6 7 8 1 1
Sample Output
7
hint
样例1:7->6->4->3 长度为4
- #include<iostream>
-
- using namespace std;
-
- const int N = 330;
-
- int dp[N][N];
- int r,c;
- int high[N][N];
-
- int mov[4][2] = {0,1,0,-1,1,0,-1,0};
-
- int dfs(int x, int y)
- {
- if(dp[x][y]) return dp[x][y];
- dp[x][y] = 1;
- for(int i=0; i<4; i++)
- {
- int nx = x + mov[i][0];
- int ny = y + mov[i][1];
- if(nx >=1 && nx <=r && ny >=1 && ny <=c && high[x][y] > high[nx][ny])
- {
- dp[x][y] = max(dp[x][y], 1+dfs(nx,ny));
- }
- }
- return dp[x][y];
- }
-
- int main()
- {
- cin>>r>>c;
- for(int i=1; i<=r; i++)
- for(int j=1; j<=c; j++)
- cin>>high[i][j];
-
- for(int i=1; i<=r; i++)
- for(int j=1; j<=c; j++)
- dp[i][j] = dfs(i,j);
-
- int ans = 0;
- for(int i=1; i<=r; i++)
- for(int j=1; j<=c; j++)
- ans = max(dp[i][j],ans);
- cout<<ans;
- return 0;
- }

LL最近沉迷于AC不能自拔,每天寝室、机房两点一线。由于长时间坐在电脑边,缺乏运动。他决定充分利用每次从寝室到机房的时间,在校园里散散步。整个HDU校园呈方形布局,可划分为n*n个小方格,代表各个区域。例如LL居住的18号宿舍位于校园的西北角,即方格(1,1)代表的地方,而机房所在的第三实验楼处于东南端的(n,n)。因有多条路线可以选择,LL希望每次的散步路线都不一样。另外,他考虑从A区域到B区域仅当存在一条从B到机房的路线比任何一条从A到机房的路线更近(否则可能永远都到不了机房了…)。现在他想知道的是,所有满足要求的路线一共有多少条。你能告诉他吗?
Input
每组测试数据的第一行为n(2=<n<=50),接下来的n行每行有n个数,代表经过每个区域所花的时间t(0<t<=50)(由于寝室与机房均在三楼,故起点与终点也得费时)。
Output
针对每组测试数据,输出总的路线数(小于2^63)。
Sample Input
- 3
- 1 2 3
- 1 2 3
- 1 2 3
- 3
- 1 1 1
- 1 1 1
- 1 1 1
Sample Output
- 1
- 6
思路:这题翻译成人话就是求(1,1)到(n,n)的路径有多少条,对路径的要求是从A区域走到B区域时,B区域到终点的距离要小于A区域。首先求出每点到终点的最短路径距离,再求出符合题目要求的路径数量。
- #include<iostream>
- #include<queue>
- #include<cstring>
- #define ll long long
-
- using namespace std;
-
- const int N = 55;
-
- int t[N][N];
- ll dp[N][N];
- int dis[N][N];
- int n;
-
- struct node{
- int x;
- int y;
- };
-
- int mov[4][2] = {0,1,0,-1,1,0,-1,0};
-
- void bfs()
- {
- queue<node> q;
- q.push({n,n});
- dis[n][n] = t[n][n];//当前只知道终点到终点的距离。
- while(!q.empty())
- {
- node a = q.front();
- q.pop();
- int x = a.x;
- int y = a.y;
- for(int i=0; i<4; i++)
- {
- int nx = x + mov[i][0];
- int ny = y + mov[i][1];
- if(nx < 1 || nx > n || ny < 1 || ny > n) continue;
- if(dis[nx][ny] > dis[x][y] + t[nx][ny] || dis[nx][ny] == 0)
- {
- dis[nx][ny] = dis[x][y] + t[nx][ny];
- q.push({nx,ny});
- }
- }
- }
- }
-
- ll dfs(int x, int y)
- {
- if(dp[x][y]) return dp[x][y];
- for(int i=0; i<4; i++)
- {
- int nx = x + mov[i][0];
- int ny = y + mov[i][1];
- if(nx <1 || nx > n || ny < 1 || ny > n) continue;
- if(dis[x][y] > dis[nx][ny])
- {
- dp[x][y] += dfs(nx,ny);
- }
- }
- return dp[x][y];
- }
-
- int main()
- {
- while(cin>>n)
- {
- memset(dp, 0, sizeof dp);
- memset(dis, 0, sizeof dis);
- dp[n][n] = 1;
-
- for(int i=1; i<=n; i++)
- for(int j=1; j<=n; j++)
- cin>>t[i][j];
-
- bfs();
-
- cout<<dfs(1,1)<<endl;
- }
- return 0;
- }

题意:四堆糖果,每次从最上面拿一个,手中最多拿五个,如果手里的糖果有相同的,就可以把糖果占为己有,最多可以占有多少对糖果。
思路:遍历所有选法。
- #include<iostream>
- #include<cstring>
- #include<algorithm>
-
- using namespace std;
-
- const int N = 55;
-
- int num[N][N];
- int vis[N];
- int n;
- int dp[N][N][N][N];
- int c[N];//这列拿到哪个糖果
-
- int dfs(int k)
- {
- int &rul = dp[c[1]][c[2]][c[3]][c[4]];
- if(rul != -1) return rul;
- rul = 0;
- if(k >= 5) return 0;
-
- for(int i=1; i<=4; i++)
- {
- if(c[i] == n) continue;
- c[i]++;
- if(vis[num[c[i]][i]])
- {
- vis[num[c[i]][i]] = 0;
- rul = max(rul, dfs(k-1)+1);
- vis[num[c[i]][i]] = 1;
- }
- else
- {
- vis[num[c[i]][i]] = 1;
- rul = max(rul, dfs(k+1));
- vis[num[c[i]][i]] = 0;
- }
- c[i]--;
- }
- return rul;
-
- }
-
-
- int main()
- {
- while(cin>>n && n)
- {
- for(int i=1; i<=n; i++)
- for(int j=1; j<=4; j++)
- cin>>num[i][j];
-
- memset(vis, 0, sizeof vis);
- memset(dp, -1, sizeof dp);
- memset(c, 0, sizeof c);
-
- cout<<dfs(0)<<endl;
- }
- return 0;
- }

Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.
For example, consider forming "tcraete" from "cat" and "tree":
String A: cat
String B: tree
String C: tcraete
As you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming "catrtee" from "cat" and "tree":
String A: cat
String B: tree
String C: catrtee
Finally, notice that it is impossible to form "cttaree" from "cat" and "tree".
Input
The first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line.
For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.
Output
For each data set, print:
Data set n: yes
if the third string can be formed from the first two, or
Data set n: no
if it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.
Sample Input
- 3
- cat tree tcraete
- cat tree catrtee
- cat tree cttaree
Sample Output
- Data set 1: yes
- Data set 2: yes
- Data set 3: no
思路:遍历所有情况的所有状态。
- #include<iostream>
- #include<cstring>
-
- using namespace std;
-
- const int N = 210;
- int dp[N][N];//当前情况下的匹配状态,0表示未匹配,1表示匹配成功,2表示匹配不成功
- char a[N],b[N],c[2*N];
-
- int dfs(int i,int j, int k)
- {
- if(dp[i][j]) return dp[i][j];
-
- if(k == strlen(c)) return dp[i][j] = 1;
-
- dp[i][j] = 2;
-
- if(a[i] == c[k]) dp[i][j] = dfs(i+1, j, k+1);
- if(b[j] == c[k] && dp[i][j] != 1) dp[i][j] = dfs(i, j+1, k+1);
-
- return dp[i][j];
- }
-
-
- int main()
- {
- int n;
- cin>>n;
- for(int i=1; i<=n; i++)
- {
- scanf("%s %s %s", a,b,c);
- memset(dp, 0, sizeof dp);
- if(dfs(0,0,0) == 1) printf("Data set %d: yes\n",i);
- else printf("Data set %d: no\n",i);
- }
- return 0;
- }

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the maximum of the total value (this number will be less than 231).
Sample Input
- 1
- 5 10
- 1 2 3 4 5
- 5 4 3 2 1
Sample Output
14
思路:遍历所有情况。
- #include<iostream>
- #include<cstring>
- #include<algorithm>
-
- using namespace std;
-
- const int N = 1010;
-
- struct node{
- int val;
- int wei;
- }bones[N];
-
- int dp[N][N];
- int n,v;
-
- int dfs(int x, int left)
- {
- if(x > n) return 0;
-
- if(dp[x][left]) return dp[x][left];
-
- if(bones[x].wei > left) return dp[x][left] = dfs(x+1, left);
-
- return dp[x][left] = max(dfs(x+1, left), dfs(x+1, left-bones[x].wei) + bones[x].val);
-
- }
-
-
- int main()
- {
- int t;
- cin>>t;
- while(t--)
- {
- cin>>n>>v;
- for(int i=1; i<=n; i++) cin>>bones[i].val;
- for(int i=1; i<=n; i++) cin>>bones[i].wei;
- cout<<dfs(1, v)<<endl;
- memset(dp, 0, sizeof dp);
- }
- return 0;
- }

有一种游戏是的玩法是这样的:
有一个n*n的格子,每个格子有一个数字。
遵循以下规则:
1. 玩家每次可以由所在格子向上下左右四个方向进行直线移动,每次移动的距离不得超过m
2. 玩家一开始在第一行第一列,并且已经获得该格子的分值
3. 玩家获得每一次移动到的格子的分值
4. 玩家下一次移动到达的格子的分值要比当前玩家所在的格子的分值要大。
5. 游戏所有数字加起来也不大,保证所有数字的和不会超过int型整数的范围
6. 玩家仅能在n*n的格子内移动,超出格子边界属于非法操作
7. 当玩家不能再次移动时,游戏结束
现在问你,玩家所能获得的最大得分是多少?
Input
有多组测试数据
每组测试样例第一行是两个整数n,m (1≤n≤100)(1≤m≤100),当n和m都是-1时为程序结束标志,直接退出即可
之后n行,每行n个数字,描述n*n的格子里的数字
Output
对于每组测试数据输出一行,这一行仅有一个整数,代表玩家所能获得的最高得分
Sample Input
- 3 1
- 1 2 5
- 10 11 6
- 12 12 7
- -1 -1
Sample Output
37
- #include<iostream>
- #include<cstring>
- #include<algorithm>
-
- using namespace std;
-
- const int N = 110;
-
- int n,m;
- int mp[N][N];
- int dp[N][N];
- int mov[4][2] = {0,1,0,-1,1,0,-1,0};
-
- int dfs(int x, int y)
- {
-
- if(dp[x][y]) return dp[x][y];
-
- dp[x][y] = mp[x][y];
-
- for(int i=0; i<4; i++)
- for(int j=1; j<=m; j++)
- {
- int nx = x + mov[i][0] * j;
- int ny = y + mov[i][1] * j;
- if(nx >= 1 && nx <= n && ny >= 1 && ny <= n && mp[nx][ny] > mp[x][y])
- dp[x][y] = max(mp[x][y] + dfs(nx, ny), dp[x][y]);
- }
- return dp[x][y];
- }
-
- int main()
- {
- while(cin>>n>>m)
- {
- if(n == -1 && m == -1) break;
- for(int i=1; i<=n; i++)
- for(int j=1; j<=n; j++)
- cin>>mp[i][j];
- cout<<dfs(1,1)<<endl;
- memset(dp, 0, sizeof dp);
- }
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。