题目为中文,题意略。

这个题目我开始用贪心做bfs两次,这样做是错的,因为两次局部的最优解并不能得出全局的最优解,以下面样例说明:

3

0   10   -1

10   10   10

1   0   10

第一次贪心后:

0   10   -1

0   0   0

1   0   0

第二次贪心后:

0   0   -1

0   0   0

1   0   0

这样贪心取到的值是50,然而我们完全有方案取到51。

为什么会造成这样的状况呢?是因为我们没有枚举出所有状态,而且说明了全局的最优不等于局部最优之和。

我们首先要确认,从左上到右下,再返回左上,和两个人同时从左上出发,最终同时到达右下是等效的。

我们定义dp[i][j][k]—-第一个人横坐标是i,第二个人横坐标是j,当前已走k步,所能获取最大值。由于小茗走的是最短路,

所以我们可以利用k求得横坐标相应的纵坐标

详见代码:

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<iostream>
  4. #include<algorithm>
  5. #define maxn 105
  6. using namespace std;
  7. typedef long long LL;
  8. const LL INF = 1e14;
  9. LL dp[maxn][maxn][2];
  10. LL value[maxn][maxn];
  11. int n;
  12. int mov1[] = {0,0,-1,-1};
  13. int mov2[] = {0,-1,0,-1};
  14. int main(){
  15. while(scanf("%d",&n) == 1){
  16. for(int k = 0;k < 2;++k){
  17. for(int i = 0;i <= n;++i){
  18. for(int j = 0;j <= n;++j){
  19. dp[i][j][k] = -INF;
  20. }
  21. }
  22. }
  23. for(int i = 1;i <= n;++i){
  24. for(int j = 1;j <= n;++j){
  25. scanf("%I64d",&value[i][j]);
  26. }
  27. }
  28. dp[1][1][0] = value[1][1];
  29. for(int k = 1;k <= 2 * n - 2;++k){
  30. for(int i = 1;i <= n;++i){
  31. for(int j = 1;j <= n;++j){
  32. dp[i][j][k & 1] = -INF;
  33. int x1 = i,x2 = j;
  34. int y1 = 1 + (k - (i - 1)),y2 = 1 + (k - (j - 1));
  35. if(y1 < 1 || y1 > n || y2 < 1 || y2 > n) continue;
  36. //printf("now is (%d,%d) (%d,%d)....\n",x1,y1,x2,y2);
  37. for(int c = 0;c < 4;++c){
  38. int xx1 = x1 + mov1[c],xx2 = x2 + mov2[c];
  39. int yy1 = 1 + ((k - 1) - (xx1 - 1)),yy2 = 1 + ((k - 1) - (xx2 - 1));
  40. if(xx1 < 1 || xx2 < 1 || yy1 < 1 || yy2 < 1) continue;
  41. if(dp[xx1][xx2][(k - 1) & 1] == -INF) continue;
  42. LL add = 0;
  43. if(x1 == x2 && y1 == y2) add = value[x1][y1];
  44. else add = value[x1][y1] + value[x2][y2];
  45. //printf("from (%d,%d) (%d,%d)\n",xx1,yy1,xx2,yy2);
  46. dp[x1][x2][k & 1] = max(dp[x1][x2][k & 1],dp[xx1][xx2][(k - 1) & 1] + add);
  47. }
  48. //printf("maxvalue: %I64d\n",dp[x1][x2][k]);
  49. }
  50. }
  51. }
  52. LL ans = dp[n][n][(2 * n - 2) & 1];
  53. printf("%I64d\n",ans);
  54. }
  55. return 0;
  56. }
  57. /*
  58. 3
  59. 0 10 -1
  60. 10 10 10
  61. 1 0 10
    */

ps:感谢fp大佬提供的数据

版权声明:本文为tiberius原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/tiberius/p/8494029.html