BZOJ 3894:文理分科
Portal:http://www.lydsy.com/JudgeOnline/problem.php?id=3894
解析:
套路太深。
这种问题从最小割的思想方法出发(网络流不过是实现最小割的一种工具罢了)。
- 割:表示对应选择的作出或否定
- 边(容量INF):纯粹的连接边(即任何时候都不会被选为割的边)
- 边(容量有限):表示某种限制
- 源、汇点:具有一类相同性质的点的集合(类似二分图)
那么我们再看这道题。
割表示不选对应决策。
S向每个人连边,容量为学文的愉♂悦值,每个人向T连边,容量为学理的愉♂悦值
对于每个人再新建一个结点,表示这个人和周围四个人都学文,S向它连边,容量为Extra的愉♂悦值,这个结点向对应五个人连边,容量为INF,这样如果五个任意一个人学理,都会使Extra的边成为割,学理同理。
最后把所有输入值求和减最小割既是答案。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
typedef long long LL;
const int maxn=100+23,maxm=maxn*maxn*16+23;
const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
const int INF=(1<<30);
struct Edge{
int u,v,cap,flow,next;
} E[maxm*2];
int n,m,ans,size,s,t,Esize,k,x,y,same_a,same_s,mini,flow,L,R;
int ind[maxn][maxn],art[maxn][maxn],sci[maxn][maxn],same_art[maxn][maxn],same_sci[maxn][maxn];
int F[maxm],last[maxm],num[maxm],cur[maxm],d[maxm],Q[maxm];
bool vis[maxm],mark;
void addedge(int x,int y,int cap)
{
E[++Esize]=(Edge){x,y,cap,0,last[x]},last[x]=Esize;
E[++Esize]=(Edge){y,x,0,0,last[y]},last[y]=Esize;
}
void BFS()
{
L=R=1,Q[1]=t,d[t]=0;
memset(vis,0,sizeof(vis)),vis[t]=1;
while (L<=R)
{
x=Q[L],L++;
for (int i=last[x];i;i=E[i].next)
if (!vis[E[i].v]) vis[E[i].v]=1,d[E[i].v]=d[x]+1,Q[++R]=E[i].v;
}
}
int calc()
{
k=INF,x=t;
while (x!=s) k=min(k,E[F[x]].cap-E[F[x]].flow),x=E[F[x]].u;
x=t;
while (x!=s) E[F[x]].flow+=k,E[F[x]^1].flow-=k,x=E[F[x]].u;
return k;
}
int Maxflow()
{
flow=0,BFS();
memset(num,0,sizeof(num));
rep(i,0,size) num[d[i]]++;
rep(i,0,size) cur[i]=last[i];
x=s;
while (d[s]<size)
{
if (x==t) flow+=calc(),x=s;
mark=0;
for (int i=cur[x];i;i=E[i].next)
if ((E[i].cap>E[i].flow)&&(d[x]==d[E[i].v]+1))
{
mark=1;
cur[x]=i,x=E[i].v,F[x]=i;
break;
}
if (!mark)
{
mini=size-1;
for (int i=last[x];i;i=E[i].next)
if (E[i].cap>E[i].flow) mini=min(mini,d[E[i].v]);
if ((--num[d[x]])==0) break;
d[x]=mini+1,num[d[x]]++;
cur[x]=last[x];
if (x!=s) x=E[F[x]].u;
}
}
return flow;
}
int main()
{
scanf("%d%d",&n,&m);
ans=0;
rep(i,1,n) rep(j,1,m) scanf("%d",&art[i][j]),ans+=art[i][j];
rep(i,1,n) rep(j,1,m) scanf("%d",&sci[i][j]),ans+=sci[i][j];
rep(i,1,n) rep(j,1,m) scanf("%d",&same_art[i][j]),ans+=same_art[i][j];
rep(i,1,n) rep(j,1,m) scanf("%d",&same_sci[i][j]),ans+=same_sci[i][j];
rep(i,1,n) rep(j,1,m) ind[i][j]=(i-1)*m+j;
s=0,t=n*m+1,Esize=1;
rep(i,1,n) rep(j,1,m) addedge(s,ind[i][j],art[i][j]),addedge(ind[i][j],t,sci[i][j]);
size=t;
rep(i,1,n)
rep(j,1,m)
{
same_a=++size,same_s=++size;
addedge(s,same_a,same_art[i][j]),addedge(same_s,t,same_sci[i][j]);
addedge(same_a,ind[i][j],INF),addedge(ind[i][j],same_s,INF);
rep(dic,0,3)
{
x=i+dx[dic],y=j+dy[dic];
if ((1<=x)&&(x<=n)&&(1<=y)&&(y<=m))
addedge(same_a,ind[x][y],INF),addedge(ind[x][y],same_s,INF);
}
}
printf("%d\n",ans-Maxflow());
return 0;
}