一道很不错的网络流题目...

刚看到这题感觉无从下手,关键是要发现一个性质:对于每一个合法的方案,每一个平原块都只和与他相邻的两个平原块相连,这样我们就能够通过最大流的模型来判断是否有解了。

那么对于带权的情况,我们考虑当前点的权值是否可以取到只取决于与当前点连接的两个平原块是否是一个方向,这样我们对一个平原块拆成2个点,分别处理X方向和Y方向,为了限制这两个方向流量和为2,我们还要再加一个点来限流,这样,如果这个2的流量是分别从X方向和Y方向流出,那么当前点的权值就能够得到,否则就不行,这个限制转化一下,变成如果当前这2个流量从一个点流出,就要花费权值的代价,那么我们可以利用费用流,通过拆边的方法进行处理,这样这个问题就解决了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define M 200000
  6 #define N 20000
  7 #define NN 305
  8 int last[N],pre[M],other[M],cap[M],cost[M];
  9 int id[NN][NN],idx[NN][NN],idy[NN][NN];
 10 int n,m,tot,l,S,T,ans,flow_sum,que[M+1],dis[N],next[N];
 11 bool vis[N];
 12 
 13 inline int read(void)
 14 {
 15     int x=0;
 16     char ch=getchar();
 17     while (ch>'9'||ch<'0') ch=getchar();
 18     while (ch>='0'&&ch<='9') 
 19     {
 20         x=x*10+ch-'0';
 21         ch=getchar();
 22     }
 23     return x;
 24 }
 25 
 26 void connect(int x,int y,int z,int w)
 27 {
 28     l++;
 29     pre[l]=last[x];
 30     last[x]=l;
 31     other[l]=y;
 32     cap[l]=z;
 33     cost[l]=w;
 34     swap(x,y);
 35     l++;
 36     pre[l]=last[x];
 37     last[x]=l;
 38     other[l]=y;
 39     cap[l]=0;
 40     cost[l]=-w;
 41 }
 42 
 43 bool spfa(void) 
 44 {
 45     memset(dis,53,sizeof dis);
 46     memset(next,0,sizeof next);
 47     dis[S]=0;que[1]=S;
 48     int h=0,t=1;
 49     while (h!=t) 
 50     {
 51         h=h%M+1;
 52         int u=que[h];vis[u]=0;
 53         for (int p=last[u];p;p=pre[p])
 54         {
 55             if (cap[p]==0) continue;
 56             int v=other[p];
 57             if (dis[v]>dis[u]+cost[p]) 
 58             {
 59                 dis[v]=dis[u]+cost[p];
 60                 next[v]=p;
 61                 if (vis[v]) continue;
 62                 t=t%M+1;
 63                 que[t]=v;
 64             }
 65         }
 66     }
 67     return dis[T]<dis[0];
 68 }
 69 
 70 void MCMF(void) 
 71 {
 72     while (spfa()) 
 73     {
 74         int flow=1e9;
 75         for (int p=next[T];p;p=next[other[p^1]]) flow=min(flow,cap[p]);
 76         for (int p=next[T];p;p=next[other[p^1]]) 
 77             cap[p]-=flow,cap[p^1]+=flow;
 78         ans-=flow*dis[T];
 79         flow_sum-=flow;
 80     }
 81 }
 82 
 83 int main()
 84 {
 85     n=read();m=read();l=1;
 86     S=++tot;T=++tot;
 87     for (int i=1;i<=n;i++) 
 88         for (int j=1;j<=m;j++) 
 89         {
 90             int x=read();
 91             if (x==1) continue;
 92             flow_sum++;
 93             id[i][j]=++tot;
 94             idx[i][j]=++tot;
 95             idy[i][j]=++tot;
 96         }
 97     for (int i=1;i<=n;i++)
 98         for (int j=1;j<=m;j++) 
 99         {
100             int x=read();
101             if (!id[i][j]) continue;
102             ans+=x;
103             if ((i+j)&1) 
104             {
105                 connect(S,id[i][j],2,0);
106                 connect(id[i][j],idx[i][j],1,0);
107                 connect(id[i][j],idy[i][j],1,0);
108                 connect(id[i][j],idx[i][j],1,x);
109                 connect(id[i][j],idy[i][j],1,x);
110                 if (i+1<=n&&id[i+1][j]) connect(idx[i][j],idx[i+1][j],1,0);
111                 if (i-1>=1&&id[i-1][j]) connect(idx[i][j],idx[i-1][j],1,0);
112                 if (j+1<=m&&id[i][j+1]) connect(idy[i][j],idy[i][j+1],1,0);
113                 if (j-1>=1&&id[i][j-1]) connect(idy[i][j],idy[i][j-1],1,0);
114             }
115             else 
116             {
117                 connect(id[i][j],T,2,0);
118                 connect(idx[i][j],id[i][j],1,0);
119                 connect(idy[i][j],id[i][j],1,0);
120                 connect(idx[i][j],id[i][j],1,x);
121                 connect(idy[i][j],id[i][j],1,x);
122             }
123         }
124     MCMF();
125     flow_sum?puts("-1"):printf("%d\n",ans);
126     return 0;
127 }

 

posted on 2017-05-18 19:32  Vergil_LY  阅读(286)  评论(0编辑  收藏  举报