• BZOJ2668: [cqoi2012]交换棋子(费用流)


    Description

    有一个nm列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。

    Input

    第一行包含两个整数nm(1<=nm<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
     

    Output

    输出仅一行,为最小交换总次数。如果无解,输出-1。

    Sample Input

    3 3
    110
    000
    001
    000
    110
    100
    222
    222
    222

    Sample Output

    4

    解题思路:

    这道题可以发现费用流肯定是可以解决的。
    问题是怎么建图。
    易知每步交换一定是一黑一白。
    所以就可以考虑每个点前后的变化来得到白变黑次数的上限。
    这个只与前后黑白状态有关。
    若状态相同,则白变黑次数=黑变白次数。
    不同则讨论即可。
    一定是一个比另外一个大一。
    这样就可以确定流入和流出上限。
    现在考虑流量守恒,发现白黑相同时无流量变化,黑白不同时边权也守恒。
    发现这样只需要新建两个新节点来达到建图的目的。
    代码:
      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 typedef long long lnt;
      6 const int oo=0x3f3f3f3f;
      7 const int di[8]={0,0,-1,1,1,1,-1,-1};
      8 const int dj[8]={-1,1,0,0,-1,1,1,-1};
      9 struct pnt{
     10     int hd;
     11     int dis;
     12     int val;
     13     int pre;
     14     int lst;
     15     bool vis;
     16 }p[100000];
     17 struct ent{
     18     int twd;
     19     int lst;
     20     int vls;
     21     int dis;
     22 }e[1000000];
     23 int cnt;
     24 int n,m;
     25 int s,t;
     26 int maxflow;
     27 int no[101][101];
     28 int st[101][101];
     29 int ed[101][101];
     30 int vl[101][101];
     31 std::queue<int>Q;
     32 void ade_(int f,int t,int v,int d)
     33 {
     34     cnt++;
     35     e[cnt].twd=t;
     36     e[cnt].vls=v;
     37     e[cnt].dis=d;
     38     e[cnt].lst=p[f].hd;
     39     p[f].hd=cnt;
     40     return ;
     41 }
     42 void adde(int f,int t,int v,int d)
     43 {
     44     ade_(f,t,v,d);
     45     ade_(t,f,0,-d);
     46     return ;
     47 }
     48 bool Spfa(void)
     49 {
     50     while(!Q.empty())Q.pop();
     51     for(int i=1;i<=t;i++)
     52     {
     53         p[i].dis=p[i].val=oo;
     54         p[i].pre=-1;
     55         p[i].vis=false;
     56     }
     57     Q.push(s);
     58     p[s].vis=true;
     59     p[s].dis=0;
     60     while(!Q.empty())
     61     {
     62         int x=Q.front();
     63         Q.pop();
     64         p[x].vis=false;
     65         for(int i=p[x].hd;i;i=e[i].lst)
     66         {
     67             int to=e[i].twd;
     68             if(p[to].dis>p[x].dis+e[i].dis&&e[i].vls)
     69             {
     70                 p[to].dis=p[x].dis+e[i].dis;
     71                 p[to].pre=x;
     72                 p[to].lst=i;
     73                 p[to].val=std::min(p[x].val,e[i].vls);
     74                 if(p[to].vis)continue;
     75                 p[to].vis=true;
     76                 Q.push(to);
     77             }
     78         }
     79     }
     80     return p[t].pre!=-1;
     81 }
     82 int Ek(void)
     83 {
     84     int ans=0;
     85     while(Spfa())
     86     {
     87         maxflow+=p[t].val;
     88         ans+=p[t].dis*p[t].val;
     89         for(int i=t;i!=s;i=p[i].pre)
     90         {
     91             e[p[i].lst].vls-=p[t].val;
     92             e[((p[i].lst-1)^1)+1].vls+=p[t].val;
     93         }
     94     }
     95     return ans;
     96 }
     97 int main()
     98 {
     99     int a1(0),a2(0);
    100     scanf("%d%d",&n,&m);
    101     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)no[i][j]=++cnt;
    102     s=cnt*3+1,t=s+1;
    103     cnt=0;
    104     for(int i=1;i<=n;i++)
    105         for(int j=1;j<=m;j++)
    106             scanf("%1d",&st[i][j]),a1+=st[i][j];
    107     for(int i=1;i<=n;i++)
    108         for(int j=1;j<=m;j++)
    109             scanf("%1d",&ed[i][j]),a2+=ed[i][j];
    110     for(int i=1;i<=n;i++)
    111         for(int j=1;j<=m;j++)
    112             scanf("%1d",&vl[i][j]);
    113     for(int i=1;i<=n;i++)
    114     {
    115         for(int j=1;j<=m;j++)
    116         {
    117             if(!st[i][j])adde(s,no[i][j],1,0);
    118             if(!ed[i][j])adde(no[i][j],t,1,0);
    119             int frm,twd;
    120             if(st[i][j]==ed[i][j])frm=twd=vl[i][j]/2;
    121             if(st[i][j]>ed[i][j])frm=(vl[i][j]+1)/2,twd=vl[i][j]/2;
    122             if(st[i][j]<ed[i][j])twd=(vl[i][j]+1)/2,frm=vl[i][j]/2;
    123             adde(no[i][j]+n*m,no[i][j],frm,0);
    124             adde(no[i][j],no[i][j]+2*n*m,twd,0);
    125             for(int d=0;d<8;d++)
    126             {
    127                 int ii=di[d]+i;
    128                 int jj=dj[d]+j;
    129                 if(!no[ii][jj])continue;
    130                 adde(no[i][j]+2*n*m,no[ii][jj]+m*n,oo,1);
    131                 
    132             }
    133         }
    134     }
    135     int ans=Ek();
    136     if(m*n-maxflow!=a1||a1!=a2)ans=-1;
    137     printf("%d
    ",ans);
    138     return 0;
    139 }
  • 相关阅读:
    Android开发环境
    安卓学习
    Shuffle'm Up POJ
    Duizi and Shunzi HDU
    Find a path HDU
    Cyclic Nacklace HDU
    Keywords Search HDU
    HDU 1495 非常可乐
    J
    Fire Game FZU
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10440725.html
Copyright © 2020-2023  润新知