vijos P1143三取方格数

描述

设有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

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值