1. 程式人生 > >BZOJ5120 無限之環(費用流)

BZOJ5120 無限之環(費用流)

  方案合法相當於要求介面之間配對,黑白染色一波,考慮網路流。有一個很奇怪的限制是不能旋轉直線型水管,考慮非直線型水管有什麼特殊性,可以發現其介面都是連續的。那麼對於旋轉水管,可以看做是把順/逆時針方向上最後的介面提到最前。於是用四個點表示某格子的四個方向,以上述方式只移動一次就能相互轉換的方向之間連費用1的邊。然後在相鄰格子可以相互匹配的方向之間連邊,跑費用流即可。注意費用流的無向邊必須按有向邊的方式建反向邊。不明白討論一大串的是在幹啥。

  

  然後就非常悲慘了。多路增廣的費用流會跑的很快,然而並不會。

#include<iostream> 
#include<cstdio>
#include
<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 10010 #define K 2010 #define S 10001 #define T 10002 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return
c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,id[K][4],p[N],d[N],q[N],pre[N],t=-1
,cnt,tot,ans,val; bool flag[N]; struct data{int to,nxt,cap,flow,cost; }edge[N<<6]; void addedge(int x,int y,int z,int cost) { t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,edge[t].cost=cost,p[x]=t; t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,edge[t].cost=-cost,p[y]=t; } inline int trans(int x,int y){return (x-1)*m+y;} inline bool isblack(int x,int y){return (x&1)^(y&1);} inline int inc(int &x){x++;if (x>cnt+3) x-=cnt+3;return x;} bool spfa() { memset(d,42,sizeof(d));d[S]=0; memset(flag,0,sizeof(flag)); int head=0,tail=1;q[1]=S; do { int x=q[inc(head)];flag[x]=0; for (int i=p[x];~i;i=edge[i].nxt) if (d[x]+edge[i].cost<d[edge[i].to]&&edge[i].flow<edge[i].cap) { d[edge[i].to]=d[x]+edge[i].cost; pre[edge[i].to]=i; if (!flag[edge[i].to]) q[inc(tail)]=edge[i].to,flag[edge[i].to]=1; } }while (head!=tail); return d[T]<N; } void ekspfa() { while (spfa()) { int v=1; for (int i=T;i!=S;i=edge[pre[i]^1].to) if (edge[pre[i]].cap==edge[pre[i]].flow) {v=0;break;} if (v) { ans++; for (int i=T;i!=S;i=edge[pre[i]^1].to) val+=edge[pre[i]].cost,edge[pre[i]].flow++,edge[pre[i]^1].flow--; } } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5120.in","r",stdin); freopen("bzoj5120.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); memset(p,255,sizeof(p)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int x=read(),u=0,v=trans(i,j); for (int k=0;k<4;k++) { id[v][k]=++cnt; if (x&(1<<k)) u++,isblack(i,j)?addedge(S,cnt,1,0):addedge(cnt,T,1,0); } tot+=u; if (x==5||x==10) continue; if (u==1||u==3) for (int k=0;k<4;k++) addedge(id[v][k],id[v][k+1&3],1,1),addedge(id[v][k+1&3],id[v][k],1,1); if (u==2) { addedge(id[v][0],id[v][2],1,1),addedge(id[v][2],id[v][0],1,1); addedge(id[v][1],id[v][3],1,1),addedge(id[v][3],id[v][1],1,1); } } if (tot&1) {cout<<-1;return 0;}tot>>=1; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (isblack(i,j)) { int v=trans(i,j); if (i>1) addedge(id[v][0],id[trans(i-1,j)][2],1,0); if (j<m) addedge(id[v][1],id[trans(i,j+1)][3],1,0); if (i<n) addedge(id[v][2],id[trans(i+1,j)][0],1,0); if (j>1) addedge(id[v][3],id[trans(i,j-1)][1],1,0); } ekspfa(); if (ans<tot) cout<<-1; else cout<<val; return 0; }