FZU 2234 牧场物语【多线程dp】

 Problem 2234 牧场物语

 Problem Description

小茗同学正在玩牧场物语。该游戏的地图可看成一个边长为n的正方形。

小茗同学突然心血来潮要去砍树,然而,斧头在小茗的右下方。

小茗是个讲究效率的人,所以他会以最短路程走到右下角,然后再返回到左上角。并且在路上都会捡到/踩到一些物品,比如说花朵,钱和大便等。

 

物品只能被取最多一次。位于某个格子时,如果格子上还有物品,就一定要取走。起点和终点上也可能有物品。

每种物品我们将为其定义一个价值,当然往返之后我们取得的物品的价值和越大越好。但是小茗同学正在认真地玩游戏,请你计算出最大的价值和。

 Input

多组数据(<=10),处理到EOF。

第一行输入正整数N(N≤100),表示正方形的大小。

接下来共N行,每行N个整数Ai,j(|Ai,j|≤10^9),表示相应对应位置上物品的价值。值为0表示没有物品。

 Output

每组数据输出一个整数,表示最大价值和。

 Sample Input

2 11 14 16 12

 Sample Output

53
 
题意自明,本来想的是直接先dp一遍,先求个最大值,再标记走过的点为0,倒着回去再dp一遍,再求个最大值,两个最大值一加就好了。但一直WA。不知道这算不算记忆化,不知道(怎么写)哪里写错了。(目前发现了边界写的不对)也请过路大牛指教:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 const int MAXN = 107;
 8 typedef long long ll;
 9 ll dp1[MAXN][MAXN], dp2[MAXN][MAXN];
10 ll a[MAXN][MAXN], path[MAXN][MAXN];
11 
12 void update(int x, int y)
13 {
14     if (x <= 0 || y <= 0) return;
15     a[x][y] = 0;
16     if (path[x][y] == 0) {
17         update(x - 1, y);
18     }
19     else if (path[x][y] == 1) {
20         update(x, y - 1);
21     }
22     else return;
23 }
24 
25 int main()
26 {
27     int N;
28     while (cin >> N)
29     {
30         for (int i = 1; i <= N; i++)
31             for (int j = 1; j <= N; j++)
32                 cin >> a[i][j];
33         memset(path, -1, sizeof(path));
34         memset(dp1, 0, sizeof(dp1));
35         memset(dp2, 0, sizeof(dp2));
36         for (int i = 1; i <= N; i++)
37             for (int j = 1; j <= N; j++)
38             {
39                 if (dp1[i - 1][j] > dp1[i][j - 1]) {
40                     dp1[i][j] = a[i][j] + dp1[i - 1][j];
41                     path[i][j] = 0;
42                 }
43                 else
44                 {
45                     dp1[i][j] = a[i][j] + dp1[i][j - 1];
46                     path[i][j] = 1;
47                 }
48             }
49         a[N][N] = 0;
50         a[1][1] = 0;
51         update(N, N);
52         for (int i = N; i >= 1; i--)
53             for (int j = N; j >= 1; j--)
54                 dp2[i][j] = a[i][j] + max(dp2[i + 1][j], dp2[i][j + 1]);
55         cout << dp1[N][N] + dp2[1][1] << endl;
56     }
57     return 0;
58 }
WA了

或者,我想难道是这个方法有漏洞?

后来,我看了好多网上的博客,感觉大牛们的想法出奇的一致!:可以把问题转化成两个人同时走。两个人同时走?我一个人来回走就不行???😔,谁让别人写的都是对的呢。。

思路就是用dp[k][x1][y1][x2][y2]表示俩人走第k步时的状态。空间复杂度高,易发现k+2=x+y,所以只记录k,x,优化掉y:dp[k][x1][x2],还不满意,感觉还高,由于本层状态只和上一层有关,所以用滚动数组,k只取0、1就好。dp[k][i][j]=max(dp[k^1][i][j],dp[k^1][i-1][[j-1],dp[k^1][i-1][j],dp[k^1][i][j-1])。(A下B下,A下B右,A右B下,A右B右四种情况转移)。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 const ll INF=1e12;
 7 const int MAXN=107;
 8 ll dp[2][MAXN][MAXN];
 9 ll a[MAXN][MAXN];
10 int N;
11 
12 int main()
13 {
14     while(cin>>N)//多组数据多组数据!!!竟然还再这里WA
15     {
16         for(int i=0;i<=N;i++)
17         for(int j=0;j<=N;j++){
18             dp[0][i][j]=dp[1][i][j]=-INF;
19             if(i>0&&j>0)
20                 cin>>a[i][j];
21         }
22         dp[0][1][1]=a[1][1];
23         int c,k;
24         for(c=0,k=1;k<=2*N-2;k++)
25         {
26             c^=1;
27             for(int i=1;i<=N;i++)
28             for(int j=1;j<=N;j++){
29                 dp[c][i][j]=max(max(dp[c^1][i][j],dp[c^1][i-1][j-1]),max(dp[c^1][i-1][j],dp[c^1][i][j-1]));
30                 if(i==j)
31                     dp[c][i][j]+=a[i][k+2-i];
32                 else
33                     dp[c][i][j]+=a[i][k+2-i]+a[j][k+2-j];
34             }
35         }
36         cout<<dp[c][N][N]<<endl;
37     }
38     return 0;
39 }
Reference Code

 

当然,也有人写记忆化写对的,但我一写就错。。。。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <string>
 4 #include <algorithm>
 5 #include <iostream>
 6 using namespace std;
 7 #define LL long long
 8 #define lson l,m,rt<<1
 9 #define rson m+1,r,rt<<1|1
10 #define lowbit(x) (x&-x)
11 
12 const int maxn = 105;
13 const LL INF = 1e15+7;    
14 
15 int n;
16 LL dp[maxn][maxn][2*maxn],a[maxn][maxn];
17 bool vis[maxn][maxn][2*maxn];
18 int d[] = {0,1};
19 
20 LL dfs(int x0,int y0,int x1,int y1,int t)
21 {
22     if(t>=2*n-1) return 0;
23     if(x0<1||x0>n||x1<1||x1>n) return -INF;
24     if(y0<1||y0>n||y1<1||y1>n) return -INF;
25 
26     if(vis[x0][x1][t]) return dp[x0][x1][t];
27     vis[x0][x1][t] = true;
28 
29     LL mx = -INF;
30     mx = max(mx,dfs(x0,y0+1,x1,y1+1,t+1));
31     mx = max(mx,dfs(x0,y0+1,x1+1,y1,t+1));
32     mx = max(mx,dfs(x0+1,y0,x1,y1+1,t+1));
33     mx = max(mx,dfs(x0+1,y0,x1+1,y1,t+1));
34 
35     dp[x0][x1][t] = mx;
36     if(x0==x1&&y0==y1) dp[x0][x1][t] += a[x0][y0];
37     else dp[x0][x1][t] += a[x0][y0]+a[x1][y1];
38 
39     return dp[x0][x1][t];
40 }
41 
42 int main()
43 {
44     while(scanf("%d",&n)!=EOF)
45     {
46         for(int i=1; i<=n; i++)
47             for(int j=1; j<=n; j++)
48                 cin>>a[i][j];
49         memset(vis,0,sizeof(vis));
50         dfs(1,1,1,1,0);
51         cout<<dp[1][1][0]<<endl;
52     }
53     return 0;
54 }
记忆化

 

 参考博客(感谢~):

【1】:http://blog.csdn.net/qq1059752567/article/details/62884319

【2】:http://blog.csdn.net/tc_to_top/article/details/51567063

【3】:http://blog.csdn.net/queuelovestack/article/details/51296950

【4】:http://m.blog.csdn.net/Tc_To_Top/article/details/51567063

【5】:http://blog.csdn.net/mengxiang000000/article/details/72851519

 

posted @ 2017-08-20 15:54  ╰追憶似水年華ぃ╮  阅读(322)  评论(0编辑  收藏  举报