码迷,mamicode.com
首页 > 其他好文 > 详细

[洛谷P2045]方格取数加强版

时间:2017-08-20 14:49:40      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:scanf   cto   cost   取数   space   一个人   tor   push   多次   

题目大意:有一个n*n的矩阵,每个格子有一个非负整数,规定一个人从(1,1)开始,只能往右或下走,走到(n,n)为止,并把沿途的数取走,取走后数变为0。这个人共取n次,求取得的数的最大总和。

解题思路:由于取多少次不确定,所以不能用dp。

我们发现,一个格子只能从左边或上面走来,且数只能取到一次,那么我们可以把此题转化为最大费用最大流问题。首先拆点,将一个点拆成x和y,然后从x到y连一条容量为1,流量为x(x为这格的数)的边,然后再连一条容量为inf,费用为0的边,这样即可保证一个点可以走多次,而数只能取一次。然后连接a和b时,从a的y向b的x连一条容量为inf,费用为0的边。最后跑最大费用最大流即可。

实现时对于(i,j),我们把这个点的x编号为$(i-1)*n+j$,y编号为$[(i-1)*n+j]*n^2$即可。

以下为EK算法代码。

C++ Code:

#include<cstdio>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 1000000
struct edge{
	int from,to,cap,cost,nxt;
}e[N];
int n,k,dis[N],a[N],pree[N],head[N],cnt;
bool vis[N];
queue<int>q;
inline void addedge(int from,int to,int cap,int cost){
	e[++cnt]=(edge){from,to,cap,cost,head[from]};
	head[from]=cnt;
	e[++cnt]=(edge){to,from,0,-cost,head[to]};
	head[to]=cnt;
}
bool spfa(int s,int t,int& flow,int& cost){
	memset(pree,0,sizeof(pree));
	memset(a,0x3f,sizeof(a));
	memset(dis,200,sizeof(dis));
	memset(vis,0,sizeof(vis));
	vis[s]=1;
	dis[s]=0;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].nxt){
			if(e[i].cap>0&&dis[e[i].to]<dis[u]+e[i].cost){
				dis[e[i].to]=dis[u]+e[i].cost;
				pree[e[i].to]=i;
				if(a[u]>e[i].cap)a[e[i].to]=e[i].cap;else a[e[i].to]=a[u];
				if(!vis[e[i].to]){
					vis[e[i].to]=1;
					q.push(e[i].to);
				}
			}
		}
	}
	if(dis[t]<1)return false;
	flow+=a[t];
	cost+=a[t]*dis[t];
	for(int i=t;i!=s;i=e[pree[i]].from){
		e[pree[i]].cap-=a[t];
		e[pree[i]^1].cap+=a[t];
	}
	return true;
}
int main(){
	cnt=1;
	scanf("%d%d",&n,&k);
	int m=n*n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			int x;
			scanf("%d",&x);
			addedge((i-1)*n+j,(i-1)*n+j+m,inf,0);
			addedge((i-1)*n+j,(i-1)*n+j+m,1,x);
			if(i>1){
				addedge((i-2)*n+j+m,(i-1)*n+j,inf,0);
			}
			if(j>1){
				addedge((i-1)*n+j-1+m,(i-1)*n+j,inf,0);
			}
			if(i==1&&j==1){
				addedge(0,1,inf,0);
			}
		}
	}
	int flow=0,cost=0;
	while(k--)
	if(!spfa(0,m<<1,flow,cost))break;
	printf("%d\n",cost);
	return 0;
}

 

[洛谷P2045]方格取数加强版

标签:scanf   cto   cost   取数   space   一个人   tor   push   多次   

原文地址:http://www.cnblogs.com/Mrsrz/p/7399814.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!