1. 程式人生 > >【Bzoj3894】文理分科(最小割)

【Bzoj3894】文理分科(最小割)

描述 擁有 pri const getch bzoj3 solution efi ini

Description

?文理分科是一件很糾結的事情!(雖然看到這個題目的人肯定都沒有糾結過)

?小P所在的班級要進行文理分科。他的班級可以用一個n*m的矩陣進行描述,每個格子代表一個同學的座位。每位同學必須從文科和理科中選擇一科。同學們在選擇科目的時候會獲得一個滿意值。滿意值按如下的方式得到:

1.如果第i行第秒J的同學選擇了文科,則他將獲得art[i][j]的滿意值,如果選擇理科,將得到science[i][j]的滿意值。

2.如果第i行第J列的同學選擇了文科,並且他相鄰(兩個格子相鄰當且僅當它們擁有一條相同的邊)的同學全部選擇了文科,則他會更開心,所以會增加same_art[i][j]的滿意值。

3.如果第i行第j列的同學選擇了理科,並且他相鄰的同學全部選擇了理科,則增加same_science[i]j[]的滿意值。 小P想知道,大家應該如何選擇,才能使所有人的滿意值之和最大。請告訴他這個最大值。

Solution

這是一道最小割的題目,關鍵在建圖

Code

#include <cstdio>
#include <algorithm>
#define N 1000010
#define Inf 0x7fffffff
using namespace std;

const int dx[]={0,0,0,1,-1};
const int dy[]={0,1,-1,0,0};
struct
info{int to,nex,f;}e[N]; int n,m,T,S,tot,nodes,head[N],Ans,cnt[N],dis[N],sum; inline void Link(int u,int v,int f){ e[++tot].to=v;e[tot].nex=head[u];head[u]=tot;e[tot].f=f; e[++tot].to=u;e[tot].nex=head[v];head[v]=tot;e[tot].f=0; } inline int read(){ int x=0,f=1;char ch=getchar(); while
(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void Init(){ n=read(),m=read(); S=0,tot=1,nodes=(T=n*m*3+1)+1; for(int i=1;i<=n*m;++i){int t=read();sum+=t;Link(S,i,t);} for(int i=1;i<=n*m;++i){int t=read();sum+=t;Link(i,T,t);} for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ int t=read(),cur=(i-1)*m+j; sum+=t; Link(S,cur+m*n,t); for(int k=0;k<5;++k){ int x=i+dx[k],y=j+dy[k]; if(x<=0||y<=0||x>n||y>m) continue; Link(cur+m*n,(x-1)*m+y,Inf); } } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ int t=read(),cur=(i-1)*m+j; sum+=t; Link(cur+2*m*n,T,t); for(int k=0;k<5;++k){ int x=i+dx[k],y=j+dy[k]; if(x<=0||y<=0||x>n||y>m) continue; Link((x-1)*m+y,cur+2*m*n,Inf); } } } int sap(int u,int d){ if(u==T) return d; int sum=0,mins=nodes; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(e[i].f>0&&dis[u]==dis[v]+1){ int save=sap(v,min(d-sum,e[i].f)); sum+=save; e[i].f-=save; e[i^1].f+=save; if(dis[S]>=nodes||sum==d) return sum; } if(e[i].f>0) mins=min(mins,dis[v]); } if(!sum){ if(!(--cnt[dis[u]])) dis[S]=nodes; else ++cnt[dis[u]=mins+1]; } return sum; } void SAP(){cnt[0]=nodes;while(dis[S]<nodes) Ans+=sap(S,Inf);} int main(){ Init(); SAP(); printf("%d\n",sum-Ans); return 0; }

【Bzoj3894】文理分科(最小割)