滑雪 POJ - 1088
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
解题思路:
使用dfs得出最大值,记忆化搜索。用的无返回值的dfs。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cmath>
using namespace std;
const int N=110;
int arr[N][N];
int vis[N][N];
int dp[N][N];
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int sum=0,ans=0,n,m;
void dfs(int x,int y,int h){
if(dp[x][y]){//如果这个点已经来过,直接得出最大sum与ans比较大小
sum+=dp[x][y];
ans=max(ans,sum);//加多少减多少
sum-=dp[x][y];
return ;
}
ans=max(ans,sum);//取最大的
int xx,yy;
for(int i=0;i<4;i++){
xx=x+dx[i];
yy=y+dy[i];
if(xx>0&&yy>0&&xx<=n&&yy<=m&&arr[xx][yy]<h&&vis[xx][yy]==0){
vis[xx][yy]=1;
sum++;
dfs(xx,yy,arr[xx][yy]);// 继续下一个点
sum--;
vis[xx][yy]=0;
}
}
return ;
}
int main(){
int res=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>arr[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
memset(vis,0,sizeof(vis));
sum=0;
ans=0;
dfs(i,j,arr[i][j]);//找这个点能划的最长距离
res=max(ans,res);//记录最大值
dp[i][j]=ans; //记录
}
}
cout<<res+1<<endl;
return 0;
}
FatMouse and Cheese (hdu-1078)
有一种游戏是的玩法是这样的:
有一个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
解题思路:
直接找最大距离,数据量过大,所以需要用记忆化数组,使用带返回参数的dfs,用dp记录dfs中每个点返回的从该点能到达的最远距离。
代码:
#include <bits/stdc++.h>
using namespace std;
int dp[110][110];
int vis[110][110];
int arr[110][110];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m;
int dfs(int x,int y){
if(dp[x][y]) return dp[x][y];//如果计算过则直接得出
int xx,yy;
for(int i=0;i<4;i++){
for(int j=1;j<=m;j++){
xx=x+dx[i]*j;
yy=y+dy[i]*j;
if(xx>0&&yy>0&&xx<=n&&yy<=n&&arr[xx][yy]>arr[x][y]&&vis[xx][yy]==0){
vis[xx][yy]=1;
dp[x][y]=max(dp[x][y],dfs(xx,yy)+arr[x][y] );//去从四个方向中的最大值
vis[xx][yy]=0;
}
}
}
return dp[x][y]=max(dp[x][y],arr[x][y]);//返回该点能走的最大距离
}
int main(){
while(cin>>n>>m&&n!=-1){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>arr[i][j];
}
}
memset(dp,0,sizeof(dp));//初始化
memset(vis,0,sizeof(vis));
vis[1][1]=1;
cout<<dfs(1,1)<<endl;
}
return 0;
}
漫步校园 (hdu-1428)
Problem Description
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
解题思路:
题意不太还理解,但不是本题重点。本题先要用bfs求出终点到各个点的最短距离,然后在用dfs求出可行的数目。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int N=55;
const int MAX=1e5;
int arr[N][N];
int ans[N][N];
int vis[N][N];
ll dp[N][N];
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int n;
ll res=0;
struct aa{
int x,y,d;
friend bool operator<(const aa &x,const aa &y){
return x.d>y.d;
}
};
int bfs(int x,int y,int d){//想用bfs求得从终点到各个点的最短距离。
priority_queue<aa>que;//因为在每个地方用的时间不同,所以需要用优先队列。
que.push({x,y,d});
ans[x][y]=d;
vis[x][y]=1;
int xx,yy;
while(que.size()){
x=que.top().x;
y=que.top().y;
d=que.top().d;
que.pop();
for(int i=0;i<4;i++){
xx=x+dx[i];
yy=y+dy[i];
if(xx>0&&yy>0&&xx<=n&&yy<=n&&vis[xx][yy]==0){
vis[xx][yy]=1;
ans[xx][yy]=arr[xx][yy]+d;
que.push({xx,yy,d+arr[xx][yy]});
}
}
}
return 0;
}
ll dfs(int x,int y){//dfs来求方法数目,dfs的返回值是方法数目,因为是记忆化搜索,不能直接用一个sum记录,每个函数都带个返回值。
if(dp[x][y]) return dp[x][y];
int xx,yy;
for(int i=0;i<4;i++){
xx=x+dx[i];
yy=y+dy[i];
if(xx>0&&yy>0&&xx<=n&&yy<=n&&ans[xx][yy]<ans[x][y]&&vis[xx][yy]==0){
vis[xx][yy]=1;
dp[x][y]+=dfs(xx,yy);
vis[xx][yy]=0;
}
}
return dp[x][y];
}
int main(){
while(cin>>n){
res=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&arr[i][j]);
}
}
bfs(n,n,arr[n][n]);
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
dp[n][n]=1;//另初始为1.
vis[1][1]=1;//标记
cout<<dfs(1,1)<<endl;
}
return 0;
}
Zipper (hdu-1501)
Problem Description
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
本题大意为:
给你三串字符串,你能用前两个组成第三个么,组成时每个字符串按顺序取出。
解题思路:
用两个坐标记录两个字符串取到字符的位置,然后用dp数组记录。用dfs来进行判断,看是否能行,能行就返回2。
Ac代码:
#include <bits/stdc++.h>
using namespace std;
int dp[220][220];
char s1[220],s2[220],s3[520];
int str(int a,int b,int c){
if(dp[a][b])//如果这个点已经算出来了直接返回。
return dp[a][b];
if(s3[c]=='