sincerit 方格取数

设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
某人从图的左上角的A 点(1,1)出发,可以向下行走,也可以向右走,直到到达右下角的B点(N,N)。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

输入格式
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出格式
只需输出一个整数,表示2条路径上取得的最大的和。

样例输入
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

样例输出
67

原先的思路是先走一遍得到一个最大值,然后把走过的地方数字变为0,再从新走一遍,可是我觉得这样做没有依据能得到最大值,然后到网上找别人怎么做的,发现题目没那么简单。
我原先的思路是得到了局部最优解,两个局部最优解加起来不一定是整体最优解
比如有个人举得例子:博客在此: https://blog.csdn.net/flx413/article/details/54882544
7
1 3 2
1 4 3
2 3 3
3 3 3
5 5 4
6 5 4
7 3 2
7 5 4
0 0 0
假如输入样例如上,如果用两次dp的方法,第一次是20,第二次是3,所以最后的权值是23。但是你再看看,我们可以把这个方格的数都取完的,第一次取的权值是17,第二次取得8,这样就是25了。显然这是一个反例,我们上述的想法是错误的。
然后正确的做法是:模拟两个人走一次得到整体最优解
dp[x1][y1][x2][y2] // 表示一个人走到(x1,y1),一个人到(x2,y2)的最大值
根据条件到达(x1,y1)的方式有两种从(x1-1,y1)到达,从(x1, y1-1)到达 这里跟聪明的kk一样的走法
这是一个人到达(x1,y1),还有一个也跟上面的走法一样,所以就有
dp[x1 - 1][y1][x2 - 1][y2]:这两个人都是从左边走过来的
dp[x1][y1 - 1][x2][y2 - 1]:这两个人都是从上边走过来的
dp[x1 - 1][y1][x2][y2 - 1]:第一人从左边走过来,第二个人从上边走过来
dp[x1][y1 - 1][x2 - 1][y2]:第一人从上边走过来,第二个人从左边走过来
当两个人走到同一个点的时候,这个点的值只能加一次,因为另一次走的时候这里的值为0
if (x1 == x2 && y1 == y2) dp[x1][y1][x2][y2] = mx + map[x1][y1];
并且由可以向下行走,也可以向右走可以发现:两个人同时走一步,无论两个人怎么选择(每人两种选择向下或向右)他们都会在同一条斜线上面 即x1+y1 == x2+y2 (八皇后问题里的左上斜线)
那么这里就可以用来剪枝

#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 15 
using namespace std;
int map[N][N];
int dp[N][N][N][N];
int main() {
  memset(dp, 0, sizeof(dp));
  memset(map, 0, sizeof(map));
  int n, x, y, w;
  scanf("%d", &n);
  while (scanf("%d%d%d", &x, &y, &w), x+y+w) {
    map[x][y] = w;
  }
  for (int x1 = 1; x1 <= n; x1++) {
    for (int y1 = 1; y1 <= n; y1++) {
      for (int x2 = 1; x2 <= n; x2++) {
        for (int y2 = 1; y2 <= n; y2++) {
          if (x1 + y1 != y2 + x2) continue;
          int mx = max(dp[x1-1][y1][x2-1][y2], dp[x1][y1-1][x2][y2-1]);
          mx = max(mx, dp[x1-1][y1][x2][y2-1]);
          mx = max(mx, dp[x1][y1-1][x2][y2-1]);
          if (x1 != x2 && y1 != y2) {
            dp[x1][y1][x2][y2] = mx + map[x1][y1] + map[x2][y2];
          } else {
            dp[x1][y1][x2][y2] = mx + map[x1][y1];
          }
        }
      }
    }
  }
  printf("%d\n", dp[n][n][n][n]);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/sincerit/article/details/84502432