• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
AC_Artist.zig_zag
然而我依然在补题、
博客园    首页    新随笔    联系   管理    订阅  订阅

bzoj2668 [cqoi2012]交换棋子

费用流题,构图非常巧妙。

考虑每个点的交换限制的约束,一看就知道是点容量,但是这里不是一分为二,而是一分为三。

首先我们把问题化简,变成对于原图上所有黑点,找到一个新图中的黑点,进行多次交换后到达。我们看到多次交换实际上是走了一条路径(这里不是最短路)。对于这条路径的起点和终点,仅进行了1次交换,而路径上的其他点都交换了2次。所以我们需要构造一种图来把这个交换次数的差异体现出来,于是:

对于每个点一分为三,分为p0,p1,p2,对于每个点,如果它是原图中得黑点,连边<p1,p0,c/2,0>,<p0,p2,(c+1)/2>,<st,p0,1,0>;如果它是新图中得黑点,连边<p1,p0,(c+1)/2>,<p0,p2,c/2,0>,<p0,ed,1,0>;如果它在两个图中都是白点,那么连边<p1,p0,c/2,0>,<p0,p2,c/2,0>。这样就可以体现出点容量的差异了。

然后对于原图中可以交换的两个点(i,j)连接<pi2,pj1,inf,1>,那么这种边每流过1的流量就意味着(i,j)交换了一次,那么费用就是最终的答案了。

chess
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 2000
  7 #define maxm 50000
  8 #define inf 2147483647
  9 using namespace std;
 10 struct et
 11 {
 12     int s,t,val,cost,next;
 13 }e[maxm];
 14 char s1[100][100],s2[100][100],s3[100][100];
 15 int a[100][100],b[100][100],c[100][100],num[100][100];
 16 int fir[maxn],q[maxm],d[maxn],pre[maxn];
 17 bool inque[maxn];
 18 int n,m,st,ed,tot,ans,b1,b2,fare;
 19 
 20 bool find()
 21 {
 22     for (int i=st;i<=ed;i++) d[i]=inf;
 23     int head=0,tail=1;
 24     q[1]=st; d[st]=0; inque[st]=1;
 25     while (head<tail)
 26     {
 27         int now=q[++head];
 28         for (int j=fir[now];j;j=e[j].next)
 29         {
 30             int k=e[j].t;
 31             if (e[j].val&&d[k]>d[now]+e[j].cost)
 32             {
 33                 pre[k]=j;
 34                 d[k]=d[now]+e[j].cost;
 35                 if (!inque[k]) q[++tail]=k,inque[k]=1;
 36             }
 37         }
 38         inque[now]=0;
 39     }
 40     return d[ed]<inf;
 41 }
 42 
 43 void fare_flow()
 44 {
 45     for (int i=1;i<=b1;i++)
 46     {
 47         find();
 48         int tmp=inf;
 49         for (int j=pre[ed];j;j=pre[e[j].s]) tmp=min(tmp,e[j].val);
 50         fare+=tmp*d[ed];
 51         ans+=tmp;
 52         for (int j=pre[ed];j;j=pre[e[j].s]) e[j].val-=tmp,e[j^1].val+=tmp;
 53     }
 54 }        
 55 
 56 void add(int x,int y,int z,int w)
 57 {
 58     e[++tot].s=x; e[tot].t=y; e[tot].val=z; e[tot].cost=w; e[tot].next=fir[x]; fir[x]=tot;
 59     e[++tot].s=y; e[tot].t=x; e[tot].val=0; e[tot].cost=-w; e[tot].next=fir[y]; fir[y]=tot;
 60 }
 61 
 62 int main()
 63 {
 64     //freopen("chess1.in","r",stdin);
 65     scanf("%d%d",&n,&m);
 66     st=0; ed=n*m*3+1; tot=1;
 67     for (int i=1;i<=n;i++)
 68         scanf("%s",s1[i]+1);
 69     for (int i=1;i<=n;i++)
 70         scanf("%s",s2[i]+1);
 71     for (int i=1;i<=n;i++)
 72         scanf("%s",s3[i]+1);
 73     for (int i=1;i<=n;i++)
 74         for (int j=1;j<=m;j++)
 75         {
 76             a[i][j]=s1[i][j]-'0';
 77             if (a[i][j]) b1++;
 78             b[i][j]=s2[i][j]-'0';
 79             if (b[i][j]) b2++;
 80             c[i][j]=s3[i][j]-'0';
 81             if (a[i][j]&&b[i][j]) a[i][j]=b[i][j]=0,b1--,b2--;
 82         }
 83     for (int i=1;i<=n;i++)
 84         for (int j=1;j<=m;j++)
 85         {
 86             int now=(i-1)*m+j;
 87             num[i][j]=now;
 88             if (a[i][j])
 89             {
 90                 add(st,now,1,0);
 91                 add(n*m+now,now,c[i][j]/2,0);
 92                 add(now,2*n*m+now,(c[i][j]+1)/2,0);
 93             }
 94             else
 95             if (b[i][j])
 96             {
 97                 add(now,ed,1,0);
 98                 add(n*m+now,now,(c[i][j]+1)/2,0);
 99                 add(now,2*n*m+now,c[i][j]/2,0);
100             }
101             else
102             {
103                 add(n*m+now,now,c[i][j]/2,0);
104                 add(now,2*n*m+now,c[i][j]/2,0);
105             }
106         }
107     for (int i=1;i<=n;i++)
108         for (int j=1;j<=m;j++)
109         {
110             if (i>1) add(2*n*m+num[i][j],n*m+num[i-1][j],inf,1);
111             if (j>1) add(2*n*m+num[i][j],n*m+num[i][j-1],inf,1);
112             if (i<n) add(2*n*m+num[i][j],n*m+num[i+1][j],inf,1);
113             if (j<m) add(2*n*m+num[i][j],n*m+num[i][j+1],inf,1);
114             if (i>1&&j>1) add(2*n*m+num[i][j],n*m+num[i-1][j-1],inf,1);
115             if (i<n&&j<m) add(2*n*m+num[i][j],n*m+num[i+1][j+1],inf,1);
116             if (i>1&&j<m) add(2*n*m+num[i][j],n*m+num[i-1][j+1],inf,1);
117             if (i<n&&j>1) add(2*n*m+num[i][j],n*m+num[i+1][j-1],inf,1);
118         }
119     //for (int i=2;i<=tot;i++) cout<<e[i].s<<' '<<e[i].t<<' '<<e[i].val<<' '<<e[i].cost<<endl;
120     fare=0;
121     if (b1==b2){
122         fare_flow();
123         if (ans!=b1) fare=-1;
124     }
125     else fare=-1;
126     printf("%d\n",fare);
127     return 0;
128 }

 

AC without art, no better than WA !
posted @ 2013-04-21 09:49  Zig_zag  阅读(1150)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3