1. 程式人生 > >BZOJ2668:[CQOI2012]交換棋子(費用流)

BZOJ2668:[CQOI2012]交換棋子(費用流)

而且 efi 格式 輸入輸出格式 ron pop 過程 中間 ive

題目描述

有一個n行m列的黑白棋盤,你每次可以交換兩個相鄰格子(相鄰是指有公共邊或公共頂點)中的棋子,最終達到目標狀態。要求第i行第j列的格子只能參與mi,j次交換。

輸入輸出格式

輸入格式:

第一行包含兩個整數n,m(1<=n, m<=20)。以下n行為初始狀態,每行為一個包含m個字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行為目標狀態,格式同初始狀態。以下n行每行為一個包含m個0~9數字的字符串,表示每個格子參與交換的次數上限。

輸出格式:

輸出僅一行,為最小交換總次數。如果無解,輸出-1。

輸入輸出樣例

輸入樣例#1: 復制
3 3
110
000
001
000
110
100
222
222
222
輸出樣例#1: 復制
4

題解

  費用流好題(說的清楚一點就是我根本不會做……)

  %%%大佬->這裏

  首先考慮,我們可以把交換操作,看作是黑色的點在移動

  一個點往下移動的話,當前點和下方的點的交換次數都加一

  然後一條移動的路徑,兩端的點移動次數加一,中間的點移動次數加二

  如果把這個過程看做網絡流的話,就會有一個問題。因為每一個點開始和結束的顏色可能不同,那麽流入和流出也不同

  如果只有一個點,就沒辦法考慮交換次數的限制

  而且如果只拆成兩個點的話,就沒辦法考慮路徑兩端的情況了

  那麽我們把每一個點拆成三個點$left,now,right$,分別表示只有流入,有流入和流出,只有流出

  所以連邊$left->now->right$

  然後相互能到達的點之間連邊,容$inf$費$0$

  然後考慮如何解決流入流出不平衡

  如果開始為白,之後黑,那麽流出必定比流入多一,開始黑,之後白,流入必定比流出多一,顏色一樣,那麽流入流出一樣

  然後交換次數最少,在相鄰的格子的邊上加上費用

  若該點在初始圖中是黑的、最終圖中是白的,那麽連邊(left,now,1,\frac{limit}{2}),(now,right,1,\frac{limit+1}{2})

  若該點在初始圖中是白的、最終圖中是黑的,那麽連邊(left,now,1,\frac{limit+1}{2}

),(now,right,1,\frac{limit}{2})

  若該點在初始圖和最終圖中顏色相同,那麽連邊(left,now,1,\frac{limit}{2}),(now,right,1,\frac{limit}{2})

  這樣就可以保證流量限制了

  然後加源,往起始的所有黑點連邊,加匯,讓最終所有黑點往它連邊

  然後在能互相到達的點之間連邊

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #define inf 0x3f3f3f3f
 7 #define l(i,j) ((i-1)*m+j)
 8 #define now(i,j) (((i-1)*m+j)+n*m)
 9 #define r(i,j) (((i-1)*m+j)+(n*m<<1))
10 using namespace std;
11 const int N=2005,M=50005;
12 int dx[]={1,1,1,0,-1,-1,-1,0},dy[]={1,0,-1,-1,-1,0,1,1};
13 int ver[M],Next[M],head[N],flow[M],edge[M],tot=1;
14 int dis[N],disf[N],Pre[N],last[N],vis[N];
15 int n,m,ans=0,S,T;
16 queue<int> q;
17 inline void add(int u,int v,int f,int e){
18     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
19     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=0,edge[tot]=-e;
20 }
21 bool spfa(){
22     memset(dis,0x3f,sizeof(dis));
23     q.push(S),dis[S]=0,disf[S]=inf,Pre[T]=-1;
24     while(!q.empty()){
25         int u=q.front();q.pop(),vis[u]=0;
26         for(int i=head[u];i;i=Next[i]){
27             int v=ver[i];
28             if(flow[i]&&dis[v]>dis[u]+edge[i]){
29                 dis[v]=dis[u]+edge[i],Pre[v]=u,last[v]=i;
30                 disf[v]=min(disf[u],flow[i]);
31                 if(!vis[v]) vis[v]=1,q.push(v);
32             }
33         }
34     }
35     return ~Pre[T];
36 }
37 int dinic(){
38     int maxflow=0;
39     while(spfa()){
40         int u=T;maxflow+=disf[T],ans+=disf[T]*dis[T];
41         while(u!=S){
42             flow[last[u]]-=disf[T];
43             flow[last[u]^1]+=disf[T];
44             u=Pre[u];
45         }
46     }
47     return maxflow;
48 }
49 int x1[25][25],x2[25][25],t1,t2;
50 char s[30];
51 int main(){
52     scanf("%d%d",&n,&m);
53     S=0,T=n*m*3+1;
54     for(int i=1;i<=n;++i){
55         scanf("%s",s+1);
56         for(int j=1;j<=m;++j)
57         if(s[j]==1){
58             ++t1,add(S,now(i,j),1,0);
59             x1[i][j]=1;
60         }
61     }
62     for(int i=1;i<=n;++i){
63         scanf("%s",s+1);
64         for(int j=1;j<=m;++j)
65         if(s[j]==1){
66             ++t2,add(now(i,j),T,1,0);
67             x2[i][j]=1;
68         }
69     }
70     if(t1!=t2) return puts("-1"),0;
71     for(int i=1;i<=n;++i){
72         scanf("%s",s+1);
73         for(int j=1;j<=m;++j){
74             t2=s[j]-0;
75             if(x1[i][j]==x2[i][j])
76             add(l(i,j),now(i,j),t2/2,0),add(now(i,j),r(i,j),t2/2,0);
77             else if(x1[i][j]&&!x2[i][j])
78             add(l(i,j),now(i,j),t2/2,0),add(now(i,j),r(i,j),(t2+1)/2,0);
79             else
80             add(l(i,j),now(i,j),(t2+1)/2,0),add(now(i,j),r(i,j),t2/2,0);
81         }
82     }
83     for(int i=1;i<=n;++i)
84     for(int j=1;j<=m;++j)
85     for(int k=0;k<8;++k){
86         int ti=i+dx[k],tj=j+dy[k];
87         if(ti<1||ti>n||tj<1||tj>m) continue;
88         add(r(i,j),l(ti,tj),inf,1);
89     }
90     if(dinic()!=t1) return puts("-1"),0;
91     printf("%d\n",ans);
92     return 0;
93 }

BZOJ2668:[CQOI2012]交換棋子(費用流)