[bzoj2668]交换棋子

基本思路是,要让所有黑点都相对应(所以首先判断黑点的个数)。
如果没有交换限制,可以按以下方法建图:源点向所有初始黑点连(1,0)的边,最终黑点向汇点连(1,0)的边,相邻的两点连边(inf,1),最小费用最大流即可。
考虑限制,我们把交换分为两种:(将1)交换进来/交换出去,因此需要两条边(三个点)来限制次数
将一个点拆成三个点,记作i1,i2和i3,设交换次数为s,分类讨论:1.如果初始和结束颜色相同,说明交换了偶数次(因为不会交换相邻两个颜色相同的点),i1连向i2(s/2,0)的边,i2连向i3(s/2,0)的边;2.如果初始是黑色,结束是白色,i1连向i2(s/2,0)的边,i2连向i3((s+1)/2,0)的边;3.如果初始是白色,结束是黑色,i1连向i2((s+1)/2,0)的边,i2连向i3(s/2,0)的边。最后还要将相邻的3向1连一条边,源点和汇点与2相连。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2005
 4 #define id (n*m+i*m+j+1)
 5 #define oo 0x3f3f3f3f
 6 struct ji{
 7     int nex,to,len,cost;
 8 }edge[N*30];
 9 queue<int>q;
10 int E,n,m,s1,s2,t,head[N],v[25][25],d[N],vis[N],from[N];
11 char s[N];
12 void add(int x,int y,int z,int w){
13     edge[E].nex=head[x];
14     edge[E].to=y;
15     edge[E].len=z;
16     edge[E].cost=w;
17     head[x]=E++;
18     if (E&1)add(y,x,0,-w);
19 }
20 bool spfa(){
21     memset(d,0x3f,sizeof(d));
22     memset(vis,0,sizeof(vis));
23     q.push(0);
24     d[0]=0;
25     while (!q.empty()){
26         int k=q.front();
27         q.pop();
28         vis[k]=0;
29         for(int i=head[k];i!=-1;i=edge[i].nex){
30             int v=edge[i].to;
31             if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){
32                 d[v]=d[k]+edge[i].cost;
33                 from[v]=i;
34                 if (!vis[v]){
35                     vis[v]=1;
36                     q.push(v);
37                 }
38             }
39         }
40     }
41     return d[t]<0x3f3f3f3f;
42 }
43 int dinic(){
44     int len,ans1=0,ans2=0;
45     while (spfa()){
46         len=oo;
47         for(int i=t;i;i=edge[from[i]^1].to)len=min(len,edge[from[i]].len);
48         ans1+=len;
49         ans2+=len*d[t];
50         for(int i=t;i;i=edge[from[i]^1].to){
51             edge[from[i]].len-=len;
52             edge[from[i]^1].len+=len;
53         }
54     }
55     if (ans1<s1)ans2=-1;
56     return ans2;
57 }
58 int main(){
59     scanf("%d%d",&n,&m);
60     memset(head,-1,sizeof(head));
61     t=3*n*m+1;
62     for(int i=0;i<n;i++){
63         scanf("%s",s);
64         for(int j=0;j<m;j++)
65             if (s[j]=='1'){
66                 s1++;
67                 add(0,id,1,0);
68                 v[i][j]++;
69             }
70     }
71     for(int i=0;i<n;i++){
72         scanf("%s",s);
73         for(int j=0;j<m;j++)
74             if (s[j]=='1'){
75                 s2++;
76                 add(id,t,1,0);
77                 v[i][j]+=2;
78             }
79     }
80     for(int i=0;i<n;i++){
81         scanf("%s",s);
82         for(int j=0;j<m;j++){
83             add(id-n*m,id,(s[j]-'0'+(v[i][j]==2))/2,0);
84             add(id,id+n*m,(s[j]-'0'+(v[i][j]==1))/2,0);
85             for(int x=-1;x<2;x++)
86                 for(int y=-1;y<2;y++)
87                     if (((x)||(y))&&(i+x>-1)&&(i+x<n)&&(j+y>-1)&&(j+y<m))add(id+n*m,id+x*m+y-n*m,oo,1);
88         }
89     }
90     if (s1!=s2)printf("-1");
91     else printf("%d",dinic());
92 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11367655.html