BZOJ 3894 网络流最小割 解题报告

来源:互联网 发布:数据一致性数据治理 编辑:程序博客网 时间:2024/06/05 20:40

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想知道,大家应该如何选择,才能使所有人的满意值之和最大。请告诉他这个最大值。

Input

第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];

Output

输出为一个整数,表示最大的满意值之和

Sample Input

3 4
13 2 4 13
7 13 8 12
18 17 0 5
8 13 15 4
11 3 8 11
11 18 6 5
1 2 3 4
4 2 3 2
3 1 0 4
3 2 3 2
0 2 2 1
0 2 4 4

Sample Output

152

【解题报告】
(原谅我没有买权限号,我也不知道我能不能A。。。)
令S集为学文,T集为学理。
每个人学文或者学理的满意度很好连边。
如果某个集合内的人都学理会获得一个满意度,那么就新加一个点,将集合内的所有人向这个点连流量为正无穷的边,再从这个点向T连一条流量为满意度的边,表示集合内任意一个人学文都要把这个点与T的边割掉。
都学文同理。
建完图之后跑最小割即可。
这里写图片描述
自己画了个图,应该会更形象些。
大神题解http://blog.csdn.net/PoPoQQQ/article/details/43968017

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=3e4+10;const int M=1e6+5;const int inf=1e8;const int dx[5]={0,1,-1,0,0};const int dy[5]={0,0,0,1,-1};struct edge {    int next,to,f;    edge(){}    edge(int _n,int _t,int _f):next(_n),to(_t),f(_f){}}e[M];int n,m,S,T,ans;int w[105][105],cnt_p;int first[N],tot=1;int q[N],d[N];inline void Add_Edges(int x,int y,int f) {    e[++tot]=edge(first[x],y,f),first[x]=tot;    e[++tot]=edge(first[y],x,0),first[y]=tot;}bool bfs() {    int l,r,x;    memset(d,-1,sizeof(d));    d[q[1]=S]=1;    for(l=r=1;l!=r+1;++l)    for(x=first[q[l]];x;x=e[x].next)        if(!~d[e[x].to]&&e[x].f)         {            d[q[++r] = e[x].to] = d[q[l]] + 1;            if(e[x].to == T) return 1;        }    return 0;}int dfs(int p,int lim) {    if (p==T||!lim) return lim;    int x,tmp,rest=lim;    for(x=first[p];x&&rest;x=e[x].next)     if(d[e[x].to]==d[p]+1&&((tmp=min(e[x].f,rest))>0))     {        rest-=(tmp=dfs(e[x].to,tmp));        e[x].f-=tmp,e[x^1].f+=tmp;        if(!rest) return lim;    }    if(rest) d[p]=-1;    return lim-rest;}inline int Dinic() {    int res=0;    while(bfs())    res+=dfs(S, inf);    return res;}inline bool in(int x, int y) {    return x&&y&&x<=n&&y<=m;}#define X i+dx[k]#define Y j+dy[k]#define p1(i,j) w[i][j]*3#define p2(i,j) w[i][j]*3+1#define p3(i,j) w[i][j]*3+2int main() {    int i,j,k,x;    scanf("%d%d",&n,&m);    for (i=1;i<=n;++i)    for (j=1;j<=m;++j)        w[i][j]=++cnt_p;    S =n*m*3+3,T=S+1;    for(i=1;i<=n;++i)    for(j=1;j<=m;++j)    {        scanf("%d",&x);        Add_Edges(S,p1(i,j),x),ans+=x;      }    for(i=1;i<=n;++i)    for(j=1;j<=m;++j)    {        scanf("%d",&x);        Add_Edges(p1(i,j),T,x),ans+=x;    }    for(i=1;i<=n;++i)    for(j=1;j<=m;++j)     {        scanf("%d",&x);        Add_Edges(S,p2(i,j),x), ans+=x;        for(k=0;k<=4;++k)            if(in(X,Y)) Add_Edges(p2(i,j),p1(X,Y),inf);    }    for(i=1;i<=n;++i)    for(j=1;j<=m;++j)     {        scanf("%d",&x);        Add_Edges(p3(i,j),T,x),ans+=x;        for(k=0;k<=4;++k)            if(in(X,Y)) Add_Edges(p1(X,Y),p3(i,j),inf);    }    printf("%d\n",ans-Dinic());    return 0;}
原创粉丝点击