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

方格取数加强版 题解

时间:2020-05-25 19:37:19      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:front   lan   turn   取数   加强   clu   i+1   mat   bool   

因为一个点的贡献只能算一次,把点拆成2个点即可,连一条流量为\(1\),费用为这个点的值,然后再连一条流量为\(+\infty\),费用为\(0\)的边,接下来对于每个点向它下方和它右方的点连一条流量为\(+\infty\),费用为\(0\)的边即可。算最大费用,边权取反。

#include <bits/stdc++.h>
int n,k,S,T,mincost;
int a[111][111];
int head[1000000],tot=1;
struct edge{int to,nxt,flow,cost;}e[1000000];
int dis[6600],vis[6600],flow[6600],pren[6600],pree[6600];
std::queue<int>q;
int GN(int x,int y){
  return x*n-n+y;
}
void add(int x,int y,int flow,int w){
	e[++tot]={y,head[x],flow,w};
	head[x]=tot;
	e[++tot]={x,head[y],0,-w};
	head[y]=tot;
}
bool spfa(){
	memset(dis,0x3f,sizeof dis);
	memset(vis,0,sizeof vis);
	memset(flow,0x3f,sizeof flow);
	q.push(S);
	vis[S]=1;
	dis[S]=0;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(int i=head[x];i;i=e[i].nxt){
			int y=e[i].to;
			vis[x]=0;
			if(e[i].flow&&dis[y]>dis[x]+e[i].cost){
				dis[y]=dis[x]+e[i].cost;
				flow[y]=std::min(flow[x],e[i].flow);
				pren[y]=x;
				pree[y]=i;
				if(!vis[y]){
					vis[y]=1;
					q.push(y);
				}
			}
		}
	}
	return dis[T]!=0x3f3f3f3f;
}
void dinic(){
	while(spfa()){
		mincost-=dis[T]*flow[T];
		for(int i=T;i!=S;i=pren[i]){
			e[pree[i]].flow-=flow[T];
			e[pree[i]^1].flow+=flow[T];
		}
	}
}
main(){
	scanf("%d%d",&n,&k);
	S=2*n*n+1,T=S+1;
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
			scanf("%d",&a[i][j]);
  for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j){
    	add(GN(i,j),GN(i,j)+n*n,1,-a[i][j]);
    	add(GN(i,j),GN(i,j)+n*n,0x3f3f3f3f,0);
    	if(i<n)add(GN(i,j)+n*n,GN(i+1,j),k,0);
    	if(j<n)add(GN(i,j)+n*n,GN(i,j+1),k,0);
    }
  add(S,GN(1,1),k,0);
  add(GN(n,n)+n*n,T,k,0);
  n=T;
	dinic();
	printf("%d\n",mincost);
	return 0;
}

方格取数加强版 题解

标签:front   lan   turn   取数   加强   clu   i+1   mat   bool   

原文地址:https://www.cnblogs.com/Skylight/p/12958524.html

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