51Nod1084 矩阵取数问题 V2

题目看这里

一个经典的dp题,典型的错误思想就是做两遍

我们考虑直接做,f[i][j][x][y]表示第一次取道i,j这个位置,第二次到了x,y这个位置

考虑这个i,j和x,y分别是从哪里转移过来,就可以得到方程

f[i][j][x][y]=max(f[i-1][j][x-1][y],f[i][j-1][x-1][y],f[i-1][j][x][y-1],f[i][j-1][x][y-1])+v[x][y]+v[i][j]

这个方程显然有x+y=i+j那么考虑去掉j,y这一维

令f[k][i][j]表示走了k步,分别走到第i行,第j行的答案,转移可以写成

f[k][i][j]=max(f[k-1][i][j],f[k-1][i-1][j-1],f[k-1][i-1][j],f[k-1][i][j-1])+s[i][k-i]+s[j][k-j]

注意如果i=j那么最后那个s[j][k-j]不要加,滚动一下就可以过了

当然这题也有网络流做法,非常的类似:

在左上面建一个源点,与(1,1)点连上,容量为2,费用为0。在右下建一个汇点,与(n,m)连上,容量为2,费用为0.
然后在中间的每个点(i,j),拆成两个点,建立两条边,一条是容量为1,费用为A[i][j]。另一条容量也是1,费用为0。再把左边和上边的点都连上。跑一次费用流就可以了

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,f[210][210],s[210][210];
int main(){
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) scanf("%d",s[i]+j);
    for(int k=2;k<=m+n;++k) for(int i=n;i;--i) for(int j=n;j;--j)
        f[i][j]=max(max(f[i][j],f[i-1][j-1]),max(f[i-1][j],f[i][j-1]))+s[i][k-i]+(i!=j?s[j][k-j]:0);
    printf("%d\n",f[n][n]);
}

posted @ 2018-04-27 17:03  扩展的灰(Extended_Ash)  阅读(110)  评论(0编辑  收藏  举报