AcWing 1027. 方格取数(走两次)

题目链接:点击这里

在这里插入图片描述
在这里插入图片描述

把走一次的过程重复两次显然是不行的,局部最优保证不了全局最优!

要求走两次,并且走过的格子,数字就被取走了,且两次走过的格子可能重合,换个思路,假设有两个人同时从左上角出发,到达右下角,这和走两次的情况是等价的!如下图:

假设两个人同时走,一个人在位置 C C ,另一个人在位置 F F ,那他们是怎么走过来的呢?显然他们可以从 [ A , D ] [A, D] [ A , E ] [A, E] [ B , D ] [B,D] [ B , E ] [B,E] 4 4 个组合的位置走到 [ C , F ] [C, F] ,类比数字三角形,我们从那四个位置的组合里选择一个最大的走过来就可以。

注意:和数字三角形所不同的是,当两个人走到同一个格子时,我们需要判断一下坐标,保证当前格子只需一次。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 12;

int a[N][N];
int f[N][N][N][N];

int Max(int a, int b, int c, int d)
{
    return max(max(a, b), max(c, d));
}

int main()
{
    int n;
    scanf("%d", &n);
    
    int r, c, w;
    while(~scanf("%d%d%d", &r, &c, &w) && r + c + w)    a[r][c] += w;
    
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            for(int ii = 1; ii <= n; ++ii)
            {
                for(int jj = 1; jj <= n; ++jj)
                {
                    f[i][j][ii][jj] = Max(f[i-1][j][ii-1][jj], f[i][j-1][ii-1][jj], f[i-1][j][ii][jj-1], f[i][j-1][ii][jj-1]);
                    
                    if(i == ii && j == jj)  f[i][j][ii][jj] += a[i][j];
                    else    f[i][j][ii][jj] += a[i][j] + a[ii][jj];
                }
            }
        }
    }
    
    printf("%d\n", f[n][n][n][n]);
    
    return 0;
}

yxc代码:在两条路径上的所有格子里,只有当横纵坐标之和相等时才有可能重合,受此启发我们可以将横纵坐标之和当做一维状态,这样可以将状态数量降至3维,且降维后每个状态可以递推出来。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 15;

int n;
int w[N][N];
int f[N*2][N][N];

int Max(int a, int b, int c, int d)
{
    return max(max(a, b), max(c, d));
}

int main()
{
    scanf("%d", &n);

    int a, b, c;
    while (cin >> a >> b >> c, a || b || c) w[a][b] = c;

    for (int k = 2; k <= n + n; k ++ )
    {
        for (int i1 = 1; i1 <= n; i1 ++ )
        {
            for (int i2 = 1; i2 <= n; i2 ++ )
            {
                int j1 = k - i1, j2 = k - i2;
                
                if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
                {
                    int &x = f[k][i1][i2];
                    x = Max(f[k-1][i1-1][i2-1], f[k-1][i1-1][i2], f[k-1][i1][i2-1], f[k-1][i1][i2]);
                    
                    if(i1 == i2)    x += w[i1][j1];
                    else    x +=  w[i1][j1] + w[i2][j2];
                }
            }
        }
    }

    printf("%d\n", f[n+n][n][n]);
    return 0;
}
发布了811 篇原创文章 · 获赞 127 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/104891718