描述
设有N*N的方格图,我们将其中的某些方格填入正整数,
而其他的方格中放入0。
某人从图得左上角出发,可以向下走,也可以向右走,直到到达右下角。
在走过的路上,他取走了方格中的数。(取走后方格中数字变为0)
此人从左上角到右下角共走3次,试找出3条路径,使得取得的数总和最大。
格式
输入格式
第一行:N (4<=N<=20)
接下来一个N*N的矩阵,矩阵中每个元素不超过80,不小于0
输出格式
一行,表示最大的总和。
样例1
样例输入1
4
1 2 3 4
2 1 3 4
1 2 3 4
1 3 2 4
1 2 3 4
2 1 3 4
1 2 3 4
1 3 2 4
样例输出1
39题解
想法一:无脑费用流。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define T 802
#define inf 1<<30
using namespace std;
int n,m,zz=1,head[805];
struct bian{int frm,to,nx,v,c;} e[10002];
int dis[805],pd[805],q[805],from[805],ans;
void insert(int x,int y,int z,int c)
{
zz++; e[zz].to=y; e[zz].frm=x; e[zz].v=z;
e[zz].c=c; e[zz].nx=head[x]; head[x]=zz;
zz++; e[zz].to=x; e[zz].frm=y; e[zz].v=0;
e[zz].c=-c; e[zz].nx=head[y]; head[y]=zz;
}
void init()
{
scanf("%d",&n);
int i,j,x;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{scanf("%d",&x);
insert((i-1)*n+j,(i-1)*n+j+n*n,1,x);
insert((i-1)*n+j,(i-1)*n+j+n*n,3,0);
if(i<n) insert((i-1)*n+j+n*n,i*n+j,3,0);
if(j<n) insert((i-1)*n+j+n*n,(i-1)*n+j+1,3,0);
}
insert(0,1,3,0);
insert(n*n*2,T,3,0);
}
bool spfa()
{
memset(dis,-1,sizeof(dis));
memset(pd,0,sizeof(pd));
q[0]=0; pd[0]=1; dis[0]=0;
int i,x,p,t=0,w=1;
while(t!=w)
{x=q[t]; t=(t+1)%805;
for(i=head[x];i;i=e[i].nx)
{p=e[i].to;
if(e[i].v>0&&dis[p]<dis[x]+e[i].c)
{dis[p]=dis[x]+e[i].c;
from[p]=i;
if(!pd[p])
{pd[p]=1; q[w]=p; w=(w+1)%805;}
}
}
pd[x]=0;
}
if(dis[T]==-1) return false;
else return true;
}
void mcf()
{
int i,x=inf;
i=from[T];
while(i)
{x=min(x,e[i].v); i=from[e[i].frm];}
i=from[T];
while(i)
{e[i].v-=x; e[i^1].v+=x; ans+=x*e[i].c; i=from[e[i].frm];}
}
int main()
{
init();
while(spfa()) mcf();
printf("%d\n",ans);
return 0;
}
想法二:四维dp:f[i][j][k][l]表示走第i步时,第一次,第二次,第三次分别走到第j,k,l列的最优情况。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,a[22][22],f[42][22][22][22];
void init()
{
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
}
void dp()
{
int i,j,k,l;
f[1][1][1][1]=a[1][1];
for(i=2;i<=n+n-1;i++)
for(j=1;j<=min(i,n);j++)
for(k=1;k<=min(i,n);k++)
for(l=1;l<=min(i,n);l++)
{f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j-1][k][l]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k-1][l]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l-1]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j-1][k-1][l]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k-1][l-1]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j-1][k][l-1]);
f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j-1][k-1][l-1]);
if(j==k&&k==l)
f[i][j][k][l]+=a[i-j+1][j];
else if(j==k)
f[i][j][k][l]+=a[i-j+1][j]+a[i-l+1][l];
else if(j==l)
f[i][j][k][l]+=a[i-j+1][j]+a[i-k+1][k];
else if(l==k)
f[i][j][k][l]+=a[i-j+1][j]+a[i-l+1][l];
else
f[i][j][k][l]+=a[i-j+1][j]+a[i-l+1][l]+a[i-k+1][k];
}
printf("%d\n",f[n+n-1][n][n][n]);
}
int main()
{
init(); dp();
return 0;
}