我明明记得写过这篇啊qwq为什么会搞丢

两题几乎一样。

Luogu P1004/P1006 方格取数/传纸条 【棋盘Dp】 By cellur925-LMLPHP

Luogu P1004/P1006 方格取数/传纸条 【棋盘Dp】 By cellur925-LMLPHP

如果再拓展到k条路,就要用网络流跑了,本蒟现在还不会。

我们容易想到四维dp,但是有一种更好的方法。

首先,先从左上到右下、再从右下到左上可以近似地等效为求从给定的起点出发走到指定位置的两条最短严格不相交路线。即两条路线同时搞。

其次,我们会记录到两个点的坐标,横纵坐标都要记录,太麻烦。要是知道当前在第几步,只枚举横坐标或是纵坐标就能求解。我们就用到这个方法。显然从左上到右下需要走n+m-2步,起点不算。然而dalao们却都习惯把起点当作第一步,走完便变成了n+m-1步,方便起见,我们使用这种表示。枚举当前在第几步(第几个格子),分别枚举两个路线的横坐标,便可知纵坐标。这是转移。

由于路线不能有冲突,所以我们特判一下如果走到了一个地方就减去一个格子的权值。

由于属于棋盘类,所以还有细节注意是否越界。

code

 #include<cstdio>
#include<algorithm> using namespace std; int n,m;
int w[][];
int f[][][]; int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&w[i][j]);
//n+m-1 ???
for(int k=;k<=n+m-;k++)
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
{
if(k-i+<||k-j+<) continue;
f[k][i][j]=max(max(f[k-][i-][j-],f[k-][i][j-]),max(f[k-][i-][j],f[k-][i][j]))+w[i][k-i+]+w[j][k-j+];
if(i==j) f[k][i][j]-=w[i][k-i+];
}
printf("%d",f[n+m-][n][n]);
return ;
}
05-26 18:46