【BZOJ】5120: [2017国家集训队测试]无限之环-最小费用流最大流

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/85226681

传送门:bzoj5120


题解

要求所有接头相连,实际上就是将边拆成入度和出度,要求满流。

将每个点拆成五个点,分别表示上下左右和中心点。按横纵坐标和奇偶进行黑白染色,源点 S S 向所有黑点的中心点连流量 + +\infty ,费用 0 0 的边,所有白点中心点连流量 + +\infty ,费用 0 0 的边。

每个点按照接头形状从中心点向对应方向点连流量 1 1 ,费用 0 0 的边。点与点之间接头相连即为相邻点之间方向点连边。(按黑白定向即可)

可以发现只有 1 , 2 , 3 1,2,3 个接头的点旋转之后是有效的,旋转即为从原方向点向旋转后连相应费用的边,分类讨论即可。


代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define rc(x) x+(lim<<2)
#define up(x) x+dr*lim
#define rt(x) x+((dr+1)&3)*lim
#define dn(x) x+((dr+2)&3)*lim
#define lf(x) x+((dr+3)&3)*lim
using namespace std;
const int N=2e4+10,M=1e6+10,inf=0x7f7f7f7f;

int n,m,sumflow,dr,lim,S,T,cst,oe;
int head[N],nxt[M],to[M],w[M],cc[M],tot=1;
int dis[N],vs[N],tim;bool inq[N];

inline void lk(int u,int v,int vv,int vc)
{
	if(oe) swap(u,v);
	to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;cc[tot]=vc;
	to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;cc[tot]=-vc;
}

deque<int>que;
inline bool spfa()
{
	memset(dis,0x7f,(T+1)<<2);int i,j,x;
	dis[T]=0;que.push_back(T);inq[T]=true;
	for(;!que.empty();){
		x=que.front();que.pop_front();
		for(i=head[x];i;i=nxt[i]){
			j=to[i];if((!w[i^1])||(dis[j]<=dis[x]-cc[i])) continue;
			dis[j]=dis[x]-cc[i];if(inq[j]) continue;
			if(que.empty() || dis[que.front()]<dis[j]) que.push_back(j);
			else que.push_front(j);inq[j]=true;
		}
		inq[x]=false;
	}
	return dis[S]<inf;
}

int dfs(int x,int f)
{
	vs[x]=tim;if(x==T) return f;
	int i,j,res,ss=0;
	for(i=head[x];i;i=nxt[i]){
		j=to[i];if(vs[j]==tim || (!w[i]) || dis[j]!=dis[x]-cc[i]) continue;
		res=dfs(j,min(f-ss,w[i]));if(!res) continue;
		w[i]-=res;w[i^1]+=res;ss+=res;cst+=cc[i]*res;if(ss==f) return ss;
	}
	return ss;
}

int main(){
	int i,j,k,x,bs=0,ct,res=0;
	scanf("%d%d",&n,&m);
	lim=n*m;S=lim*5+1;T=S+1;
	for(i=1;i<=n;++i)
	  for(j=1;j<=m;++j){
	  	++bs;scanf("%d",&x);dr=oe=0;ct=rc(bs);
	  	((i+j)&1)?lk(S,ct,inf,0):lk(ct,T,inf,0);
	  	oe=(i+j)&1;
	  	if(i>1) lk(dn(bs-m),up(bs),1,0);
	  	if(j>1) lk(rt(bs-1),lf(bs),1,0);
	  	for(k=0;k<4;++k) if((x>>k)&1)
	  		lk(bs+k*lim,ct,1,0),sumflow++;
	  	switch(x){
	  		case 8:++dr;
	  		case 4:++dr;
	  		case 2:++dr;
	  		case 1:
	  			lk(rt(bs),up(bs),1,1);
	  			lk(lf(bs),up(bs),1,1);
	  			lk(dn(bs),up(bs),1,2);
	  			break;
	  		case 9:++dr;
	  		case 12:++dr;
	  		case 6:++dr;
	  		case 3:
	  			lk(dn(bs),up(bs),1,1);
	  			lk(lf(bs),rt(bs),1,1);
	  			break;
	  		case 13:++dr;
	  		case 14:++dr;
	  		case 7:++dr;
	  		case 11:
	  			lk(dn(bs),lf(bs),1,1);
	  			lk(dn(bs),rt(bs),1,1);
	  			lk(dn(bs),up(bs),1,2);
	  			break;
	  	}
	  }
	for(;spfa();){
		for(vs[T]=tim;vs[T]==tim;){
			tim++;res+=dfs(S,inf);
		}
	}
	if((res<<1)!=sumflow) cst=-1;
	printf("%d",cst);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/85226681