[BZOJ3894]文理分科(最小割)

(1) 对每个位置建一个点F1,S向这个点连art[i][j]的边,这个点向T连science[i][j]的边。

(2) 对每个位置再建一个点F2,S向这个点连same_art[i][j]的边,这个点向F1的相邻的五个点连inf的边。

(3) 对每个位置再建一个点F3,这个点向T连same_science[i][j]的边,F1的相邻的五个点向这个点连inf的边。

先让ans等于所有art,science,same_art,same_science的和,减去最大流就是答案。

可以这么理解:

首先ans是将所有收益全部占全的答案,现在要减去的是冲突的收益。冲突分三种,一个点不能既选art又选science,只有相邻五个全部选同一科才会触发same收益,同一个点的两个same收益不可能同时触发。我们的建图只需要满足这三种情况都不出现即可。

第一种冲突显然由(1)直接解决了。

第二种冲突由(2)和(3)解决,可以发现,inf边肯定不会被割掉,也就是说“same[i][j]”和“i,j的五个相邻点存在选另一科”这两个只能选一个。

第三种冲突也很显然,一个点不可能art[i][j]和science[i][j]都不被割掉。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 5 using namespace std;
 6 
 7 const int N=30010,M=400010,K=110,inf=1000000000;
 8 int n,m,ans,x,S,T,tot,cnt=1,F1[K][K],F2[K][K],F3[K][K];
 9 int to[M],f[M],nxt[M],h[N],dis[N],q[M];
10 
11 void add(int u,int v,int w){
12     to[++cnt]=v; f[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt;
13     to[++cnt]=u; f[cnt]=0; nxt[cnt]=h[v]; h[v]=cnt;
14 }
15 
16 bool bfs(){
17     rep(i,0,T) dis[i]=0; q[1]=S; dis[S]=1;
18     for (int st=0,ed=1; st<ed; ){
19         int x=q[++st];
20         For(i,x) if (f[i] && !dis[k=to[i]]) dis[k]=dis[x]+1,q[++ed]=k;
21     }
22     return dis[T];
23 }
24 
25 int dfs(int x,int lim){
26     if (x==T) return lim;
27     int c=0;
28     For(i,x) if (f[i] && dis[k=to[i]]==dis[x]+1){
29         int t=dfs(k,min(lim-c,f[i]));
30         c+=t; f[i]-=t; f[i^1]+=t;
31         if (c==lim) return c;
32     }
33     if (!c) dis[x]=-1;
34     return c;
35 }
36 
37 int main(){
38     freopen("bzoj3894.in","r",stdin);
39     freopen("bzoj3894.out","w",stdout);
40     scanf("%d%d",&n,&m); S=3*n*m+1; T=3*n*m+2;
41     rep(i,1,n) rep(j,1,m) scanf("%d",&x),ans+=x,add(S,F1[i][j]=++tot,x);
42     rep(i,1,n) rep(j,1,m) scanf("%d",&x),ans+=x,add(F1[i][j],T,x);
43     rep(i,1,n) rep(j,1,m){
44         scanf("%d",&x); ans+=x;
45         add(S,F2[i][j]=++tot,x); add(F2[i][j],F1[i][j],inf);
46         if (i>1) add(F2[i][j],F1[i-1][j],inf);
47         if (i<n) add(F2[i][j],F1[i+1][j],inf);
48         if (j>1) add(F2[i][j],F1[i][j-1],inf);
49         if (j<m) add(F2[i][j],F1[i][j+1],inf);
50     }
51     rep(i,1,n) rep(j,1,m){
52         scanf("%d",&x); ans+=x;
53         add(F3[i][j]=++tot,T,x); add(F1[i][j],F3[i][j],inf);
54         if (i>1) add(F1[i-1][j],F3[i][j],inf);
55         if (i<n) add(F1[i+1][j],F3[i][j],inf);
56         if (j>1) add(F1[i][j-1],F3[i][j],inf);
57         if (j<m) add(F1[i][j+1],F3[i][j],inf);
58     }
59     while (bfs()) ans-=dfs(S,inf);
60     printf("%d\n",ans);
61     return 0;
62 }

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/9295952.html