1. 程式人生 > >FZU 2234 牧場物語【多線程dp】

FZU 2234 牧場物語【多線程dp】

tle 定義 math type play inf 一加 i++ data

技術分享 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

FZU 2234 牧場物語【多線程dp】