【BZOJ】5120: [2017國家集訓隊測試]無限之環-最小費用流最大流
阿新 • • 發佈:2019-01-03
傳送門:bzoj5120
題解
要求所有接頭相連,實際上就是將邊拆成入度和出度,要求滿流。
將每個點拆成五個點,分別表示上下左右和中心點。按橫縱座標和奇偶進行黑白染色,源點 向所有黑點的中心點連流量 ,費用 的邊,所有白點中心點連流量 ,費用 的邊。
每個點按照接頭形狀從中心點向對應方向點連流量 ,費用 的邊。點與點之間接頭相連即為相鄰點之間方向點連邊。(按黑白定向即可)
可以發現只有 個接頭的點旋轉之後是有效的,旋轉即為從原方向點向旋轉後連相應費用的邊,分類討論即可。
程式碼
#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;
}