2014百度之星资格赛 1004:Labyrinth(DP)

Labyrinth

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1507    Accepted Submission(s): 520


Problem Description
度度熊是一只喜欢探险的熊,一次偶然落进了一个m*n矩阵的迷宫,该迷宫只能从矩阵左上角第一个方格开始走,只有走到右上角的第一个格子才算走出迷宫,每一次只能走一格,且只能向上向下向右走以前没有走过的格子,每一个格子中都有一些金币(或正或负,有可能遇到强盗拦路抢劫, 度度熊身上金币可以为负,需要给强盗写欠条),度度熊刚开始时身上金币数为0,问度度熊走出迷宫时候身上最多有多少金币?
 

 

Input
输入的第一行是一个整数T(T < 200),表示共有T组数据。
每组数据的第一行输入两个正整数m,n(m<=100,n<=100)。接下来的m行,每行n个整数,分别代表相应格子中能得到金币的数量,每个整数都大于等于-100且小于等于100。
 

 

Output
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
每组测试数据输出一行,输出一个整数,代表根据最优的打法,你走到右上角时可以获得的最大金币数目。
 

 

Sample Input
2
3 4
1 -1 1 0
2 -2 4 2
3 5 1 -90
2 2
1 1
1 1
 

 

Sample Output
Case #1:
18
Case #2:
4
 
  DP题
  一开始用DFS做的,果断超时。看讨论版才发现需要用DP,当时就蔫了,后来还是查了网上的题解,才明白怎么用DP解这道题,对DP的理解更深了。下面是思路:
  思路:这道题的思路是一列列的确定每一个格子的最大金币数。先确定第一列的最大金币数,因为只能向下走,所以很好求。之后每一列每格的最大金币数可以由前一列求得。
  例如要求dp[i][j](dp[][]的含义是走到这个位置的最大金币数),则从前一列有3种走法到这个格子:
  1、它的左边一个格子,即a[i][j-1],直接向右走一个格子;
  2、a[i][j-1]上面的所有格子,可以先向右走一个格,然后向下一直走到a[i][j]的位置;
  3a[i][j-1]下面的所有格子,可以先向右走一个格,然后向上一直走到a[i][j]的位置。
  遍历上述所有路径的过程中需要记录一个最大值,最后这个值就是dp[i][j]的值。
  由此可知,确定该位置的每一种路径,需要遍历m次。而你需要确定每一列的每一个格子的dp[][]值,所以这个算法的时间复杂度为O(n*m *m)
  代码
 1 #include <iostream>

 2 #include <stdio.h>

 3 using namespace std;  4 #define inf 0x7fffffff

 5 int a[110][110];  6 int dp[110][110];    //记录走到某一位置的金币最大值

 7 int m,n;  8 void DP()  9 { 10     int i,j,k; 11     dp[1][1] = a[1][1]; 12     for(i=2;i<=m;i++)    //初始化第一列

13         dp[i][1] = dp[i-1][1] + a[i][1]; 14     for(i=2;i<=n;i++){    //每一列 a[][i]

15         for(j=1;j<=m;j++){    //每一列的每一个位置 a[j][i] 16             //有三种路径到达这个位置。 17             //1.它左边的位置直接向右走过来。 18             //2.它左边的位置的上面所有位置向右再一直向下走到这个位置。 19             //3.它左边的位置的下面所有位置向右再一直向上走到这个位置。 20             //不断比较,在这个位置处 dp[j][i] 记录以上3条路径的最大值。即为走到这个位置的能拥有的最大金币数。 21             //这是以 a[j][i] 为重心考虑,遍历到达 a[j][i]的三种路径,求出最大值

22             int t = dp[j][i-1] + a[j][i]; 23             if(t>dp[j][i]) 24                 dp[j][i] = t; 25             for(k=j-1;k>=1;k--){ 26                 //a[k][i-1] --> a[j][i]这个位置所拥有的金币数

27                 t = t-dp[k+1][i-1]+dp[k][i-1]+a[k][i]; 28                 if(t>dp[j][i]) 29                     dp[j][i] = t; 30  } 31             t = dp[j][i-1] + a[j][i]; 32             for(k=j+1;k<=m;k++){ 33                 //a[k][i-1] --> a[j][i]这个位置所拥有的金币数

34                 t = t-dp[k-1][i-1]+dp[k][i-1]+a[k][i]; 35                 if(t>dp[j][i]) 36                     dp[j][i] = t; 37  } 38  } 39  } 40 } 41 int main() 42 { 43     int i,j,Case,T; 44     scanf("%d",&T); 45     for(Case=1;Case<=T;Case++){ 46         scanf("%d%d",&m,&n); 47         for(i=1;i<=m;i++)    //输入迷宫,初始化dp[][]

48             for(j=1;j<=n;j++){ 49                 scanf("%d",&a[i][j]); 50                 dp[i][j] = -inf; 51  } 52         printf("Case #%d:\n",Case); 53  DP(); 54         printf("%d\n",dp[1][n]); 55  } 56     return 0; 57 }

 

  贴上超时的DFS代码

 1 #include <iostream>

 2 #include <stdio.h>

 3 #include <string.h>

 4 using namespace std;  5 int Max;  6 int a[110][110];  7 bool isv[110][110];  8 int dx[3] = {1,-1,0};  9 int dy[3] = {0,0,1}; 10 int m,n; 11 bool judge(int x,int y) 12 { 13     if(x<1 || x>m || y<1 || y>n) 14         return true; 15     if(isv[x][y]) 16         return true; 17     return false; 18 } 19 void dfs(int x,int y,int money) 20 { 21     if(x==1 && y==n){ 22         if(money>Max) 23             Max=money; 24  } 25     int i; 26     for(i=0;i<3;i++){ 27         int nx = x+dx[i]; 28         int ny = y+dy[i]; 29         if(judge(nx,ny)) 30             continue; 31         //可以走

32         isv[nx][ny] = true; 33         dfs(nx,ny,money+a[nx][ny]); 34         isv[nx][ny] = false; 35  } 36 } 37 int main() 38 { 39     int i,j,Case,T; 40     scanf("%d",&T); 41     for(Case=1;Case<=T;Case++){ 42         scanf("%d%d",&m,&n); 43         for(i=1;i<=m;i++) 44             for(j=1;j<=n;j++) 45                 scanf("%d",&a[i][j]); 46         printf("Case #%d:\n",Case); 47         Max=0; 48         memset(isv,0,sizeof(isv)); 49         isv[1][1] = true; 50         dfs(1,1,a[1][1]); 51         printf("%d\n",Max); 52  } 53     return 0; 54 }

 

  Freecode : www.cnblogs.com/yym2013

你可能感兴趣的:(int)