标签:
/*
这道题要解决两个问题
1)状态和状态方程
2)怎么保证每走一步,所形成的路径不相交,以保证最后生成的完整路径不相交。
(1)状态:
dp[i][j][k][l] = 小渊传递的纸条到[i][j]的位置,小轩传递的纸条到[k][l]的位置时,好心程度和的最大值。
(2)状态方程:
看到题目,直接的想法是:
按题意,小渊从左上角->右下角,小轩从右下角->左上角。但是,路径在走的时候,怎么才能保证路径不相交,我想不出来办法了。。。
仔细想,题目要求:
两条路径的头尾坐标相同(出发点选择不同),但实际上选择头或尾哪个点作为出发点,都是无所谓的。
那么就让两条路径都从点[1][1]出发,此种做法有比较简单的办法保证路径不相交。
dp[i][j][k][l] = arr[i][j] + arr[k][l] +
max{dp[i-1][j][k-1][l], dp[i-1][j][k][l-1], dp[i][j-1][k-1][l], dp[i][j-1][k][l-1]}
(3)控制条件(保证获得不相交的路径):
两条路径都从点[1][1]出发,让两条路径并行去走,并保证小渊走到点[i][j],小轩走到[k][l]时,所形成的路径不相交:
关键:
1) 并行 (i+j)=(k+l)
2) 不相交 if (i==k)&&(j==l) return false;
(4)得到答案:
两条路径要想到达点[m][n],则两条路径选择到达目的地的点必然选择:[m][n-1],[m-1][n]
(因为到达目的地,只有两种动作:向下,向左)
故:ans = max(dp[m][n - 1][m - 1][n], dp[m - 1][n][m][n-1])
*/
1 #define _CRTDBG_MAP_ALLOC 2 #include <stdlib.h> 3 #include <crtdbg.h> 4 void fnExit1(void) 5 { 6 _CrtDumpMemoryLeaks(); 7 } 8 9 #define _CRT_SECURE_NO_WARNINGS 10 #define HOME 11 12 #include <iostream> 13 #include <cstdlib> 14 #include <cstdio> 15 #include <cstddef> 16 #include <iterator> 17 #include <algorithm> 18 #include <locale> 19 #include <cmath> 20 #include <vector> 21 #include <cstring> 22 using namespace std; 23 const int INF = 0x3f3f3f3f; 24 const int MaxN = 30; 25 const int Max = 55; 26 27 int m, n; 28 int arr[Max][Max]; 29 int dp[Max][Max][Max][Max]; 30 int step[2][2] = { {-1, 0}, {0, -1} }; // 向下,向左 31 32 bool Check(int x1, int y1, int x2, int y2) 33 { 34 // 防止越界 35 if ((x1 <= 0) || (y1 <= 0) || (x2 <= 0) || (y2 <= 0)) 36 { 37 return false; 38 } 39 // 两条路径不能相交 40 if ((x1 == x2) && (y1 == y2)) 41 { 42 return false; 43 } 44 return true; 45 } 46 47 void Solve() 48 { 49 int x1, y1, x2, y2; 50 for (int i = 1; i <= m; ++i) 51 { 52 for (int j = 1; j <= n; ++j) 53 { 54 for (int k = 1; k <= m; ++k) 55 { 56 57 // 两条路径并行走,则:(i+j)=(k+l) 58 if (i + j - k <= 0) break; 59 int l = i + j - k; 60 if (!Check(i, j, k, l)) continue; 61 int maxVal = 0; 62 for (int p = 0; p < 2; ++p) 63 { 64 for (int q = 0; q < 2; ++q) 65 { 66 x1 = i + step[p][0]; 67 y1 = j + step[p][1]; 68 x2 = k + step[q][0]; 69 y2 = l + step[q][1]; 70 if (Check(x1, y1, x2, y2)) 71 { 72 maxVal = max(maxVal, dp[x1][y1][x2][y2]); 73 } 74 } 75 } 76 dp[i][j][k][l] = max(dp[i][j][k][l], maxVal + arr[i][j] + arr[k][l]); 77 } 78 } 79 } 80 // 两条路径要想到达点[m][n],则两条路径的点必然选择:[m][n-1],[m-1][n] 81 int ans = max(dp[m][n - 1][m - 1][n], dp[m - 1][n][m][n-1]); 82 //for (int i = 1; i <= m; ++i) 83 //{ 84 // for (int j = 1; j <= n; ++j) 85 // { 86 // for (int k = 1; k <= m; ++k) 87 // { 88 // for (int l = 1; l <= n; ++l) 89 // { 90 // //cout << "(" << i << ", " << j << ", " << k << ", " << l << ")" << " : " << dp[i][j][k][l] << endl; 91 // cout << dp[i][j][k][l] << "-->" << dp[k][l][i][j] << endl; 92 // /* 两条路径出发点相同,没有区分两条路径,也就是小渊和小轩怎么分配这两条路径都可以, 93 // 所以dp[i][j][k][l]=dp[k][l][i][j] 94 // */ 95 // } 96 // } 97 // } 98 //} 99 cout << ans << endl; 100 //cout << dp[m][n - 1][m - 1][n] << " " << dp[m - 1][n][m][n - 1] << endl; // 两个值相同 101 } 102 103 int main() 104 { 105 106 #ifdef HOME 107 //freopen("in", "r", stdin); 108 //freopen("out", "w", stdout); 109 //atexit(fnExit1); 110 #endif 111 112 memset(dp, 0, sizeof(0)); 113 cin >> m >> n; 114 for (int i = 1; i <= m; ++i) 115 { 116 for (int j = 1; j <= n; ++j) 117 { 118 cin >> arr[i][j]; 119 } 120 } 121 Solve(); 122 123 124 #ifdef HOME 125 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl; 126 _CrtDumpMemoryLeaks(); 127 system("pause"); 128 #endif 129 return 0; 130 }
棋盘型动态规划 之 CODE[VS] 1169 传纸条 2008年NOIP全国联赛提高组
标签:
原文地址:http://www.cnblogs.com/shijianming/p/4943978.html