1. 程式人生 > >LOJ 2321 清華集訓2017 無限之環 拆點+最小費用最大流

LOJ 2321 清華集訓2017 無限之環 拆點+最小費用最大流

題面:中文題面,這裡不佔用篇幅

 

分析:

  看到題面,我就想棄療……

  但是作為任務題單,還是抄了題解……

  大概就是將每個格子拆點,拆成五個點,上下左右的觸點和一個負責連源匯點的點(以下簡稱本點)。

  這個這個本點要根據初始形態向相應的觸點連線費用為0容量為1的邊,再由旋轉規則,使初始觸點向相應的觸點連線費用為旋轉次數的邊,然後相鄰的格子觸點相連?

  反正很亂就是了。如果再寫一遍,我應該不會寫罷……

程式碼:(這份程式碼在Luogu上不開O2會TLE十八組資料……開了才能過,在loj是可過的)

 1 #include<bits/stdc++.h>
 2
#define up(u) u+tn*sm 3 #define ri(u) u+((tn+1)&3)*sm 4 #define dn(u) u+((tn+2)&3)*sm 5 #define le(u) u+((tn+3)&3)*sm 6 #define md(u) u+(sm<<2) 7 using namespace std;queue<int>q; 8 const int N=20005,M=200005,inf=0x3f3f3f3f; 9 struct node{int y,z,f,nxt;}e[M]; 10 int mf=0,f[N],lst[N],ans=0
;bool vis[N]; 11 int sm,c=1,S=0,T,h[N],d[N],pre[N],n,m,k; 12 void add(int x,int y,int f,int z,int tp){ 13 if(tp) swap(x,y); 14 e[++c]=(node){y,z,f,h[x]};h[x]=c; 15 e[++c]=(node){x,-z,0,h[y]};h[y]=c; 16 } bool spfa(){ 17 for(int i=S;i<=T;i++) pre[i]=-1, 18 f[i]=inf,lst[i]=vis[i]=0
,d[i]=inf; 19 q.push(S);d[S]=0;pre[S]=0; 20 while(q.size()){ 21 int x=q.front();q.pop();vis[x]=0; 22 for(int i=h[x],y;i;i=e[i].nxt) 23 if(d[y=e[i].y]>d[x]+e[i].z&&e[i].f){ 24 d[y]=d[x]+e[i].z;pre[y]=x;lst[y]=i; 25 f[y]=min(f[x],e[i].f); 26 if(!vis[y]) vis[y]=1,q.push(y); 27 } 28 } return (pre[T]!=-1); 29 } void solve(){ 30 while(spfa()){ 31 ans+=d[T]*f[T];int x=T;mf+=f[T]; 32 while(x) e[lst[x]].f-=f[T], 33 e[lst[x]^1].f+=f[T],x=pre[x]; 34 } return ; 35 } int main(){ 36 k=1;int t,sp,tn,tf=0,mc=0; 37 scanf("%d%d",&n,&m);sm=n*m;T=sm*5+1; 38 for(int i=0;i<n;i++) 39 for(int j=0;j<m;j++,k++){ 40 tn=0;t=(i+j)&1; 41 if(t) add(S,md(k),inf,0,0); 42 else add(md(k),T,inf,0,0); 43 if(i) add(dn(k-m),up(k),1,0,t); 44 if(j) add(ri(k-1),le(k),1,0,t); 45 scanf("%d",&sp); 46 if(sp&1) add(up(k),md(k),1,0,t),tf++; 47 if(sp&2) add(ri(k),md(k),1,0,t),tf++; 48 if(sp&4) add(dn(k),md(k),1,0,t),tf++; 49 if(sp&8) add(le(k),md(k),1,0,t),tf++; 50 switch(sp){ 51 case 8:tn++; 52 case 4:tn++; 53 case 2:tn++; 54 case 1: 55 add(ri(k),up(k),1,1,t); 56 add(dn(k),up(k),1,2,t); 57 add(le(k),up(k),1,1,t);break; 58 case 9:tn++; 59 case 12:tn++; 60 case 6:tn++; 61 case 3: 62 add(dn(k),up(k),1,1,t); 63 add(le(k),ri(k),1,1,t);break; 64 case 13:tn++; 65 case 14:tn++; 66 case 7:tn++; 67 case 11: 68 add(dn(k),le(k),1,1,t); 69 add(dn(k),up(k),1,2,t); 70 add(dn(k),ri(k),1,1,t);break; 71 } 72 } solve(); 73 printf("%d",tf==mf<<1?ans:-1);return 0; 74 }
費用流