• [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
  • 相关阅读:
    Linux命令——getfacl、setfacl
    Linux命令——groups
    Linux命令——gdisk、fdisk、partprobe
    Linux命令——parted
    Linux命令——blkid
    Linux命令——chattr、lsattr
    Linux命令——od
    Linux命令——basename、dirname
    Linux命令——chgrp、chown、chmod
    Linux命令——pidof
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/11367655.html
Copyright © 2020-2023  润新知