【BZOJ2127】happiness 网络流

来源:互联网 发布:ubuntu subline 编辑:程序博客网 时间:2024/06/14 00:47

题目描述

  有n×m个人,排成一个n×m的矩阵。每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。问全班喜悦值的和最大是多少。

  n,m100

题解

  先把问题简化,考虑只有两个人,甲选文科的喜悦值为a,甲选理科的喜悦值为b,乙选文科的喜悦值为c,乙选理科的喜悦值为d,两人同时选文科的喜悦值为e,两人同时选理科的喜悦值为f

  两个人同时选文或同时选理会有额外喜悦值,这并不太好处理。考虑转化一下。先把两人选文的喜悦值a,c加上两人同时选文科的喜悦值的一半e2。如果只有一人选(即两人选的不同),那么就要减掉e2。理科同理。

  这样就是一个网络流的标准模型了。

  最后拿a+b+c+d+e+f减掉最小割就是答案。

  e,f有可能是奇数,可以把所有边的容量×2,最后再除回来。

  可以得到以下的网络:

  这里写图片描述

  多个人的情况和两个人的情况类似,合在一起处理即可。

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<cmath>#include<functional>#include<queue>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(int &a,int &b){    if(a>b)        swap(a,b);}void open(const char *s){#ifndef ONLINE_JUDGE    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}int rd(){    int s=0,c;    while((c=getchar())<'0'||c>'9');    do    {        s=s*10+c-'0';    }    while((c=getchar())>='0'&&c<='9');    return s;}int upmin(int &a,int b){    if(b<a)    {        a=b;        return 1;    }    return 0;}int upmax(int &a,int b){    if(b>a)    {        a=b;        return 1;    }    return 0;}int v[1000010];int w[1000010];int t[1000010];int h[10010];int cnt=0;void add(int x,int y,int z){    cnt++;    v[cnt]=y;    w[cnt]=z;    t[cnt]=h[x];    h[x]=cnt;}int S,T;int d[10010];int e[10010];int cur[10010];int num;int op(int x){    return ((x-1)^1)+1;}queue<int> q;void bfs(){    memset(d,-1,sizeof d);    memcpy(cur,h,sizeof h);    q.push(T);    d[T]=0;    int i,x;    while(!q.empty())    {        x=q.front();        q.pop();        e[d[x]]++;        for(i=h[x];i;i=t[i])            if(w[op(i)]&&d[v[i]]==-1)            {                d[v[i]]=d[x]+1;                q.push(v[i]);            }    }}int dfs(int x,int flow){    if(x==T)        return flow;    int s=0,c;    int &i=cur[x];    for(;i;i=t[i])        if(d[v[i]]==d[x]-1&&w[i])        {            c=dfs(v[i],min(flow,w[i]));            s+=c;            flow-=c;            w[i]-=c;            w[op(i)]+=c;            if(!flow)                return s;        }    e[d[x]]--;    if(!e[d[x]])        d[S]=num;    e[++d[x]]++;    cur[x]=h[x];    return s;}int maxflow(){    bfs();    int ans=0;    while(d[S]<=num-1)        ans+=dfs(S,0x7fffffff);    return ans;}int m1[110][110];int m2[110][110];int m3[110][110];int m4[110][110];int m5[110][110];int m6[110][110];int n,m;int id(int x,int y){    return (x-1)*m+y;}int a1[110][110];int a2[110][110];int a3[110][110];int a4[110][110];int main(){    open("bzoj2127");    scanf("%d%d",&n,&m);    int i,j;    int sum=0;    for(i=1;i<=n;i++)        for(j=1;j<=m;j++)        {            scanf("%d",&m1[i][j]);            sum+=2*m1[i][j];            a1[i][j]+=2*m1[i][j];        }    for(i=1;i<=n;i++)        for(j=1;j<=m;j++)        {            scanf("%d",&m2[i][j]);            sum+=2*m2[i][j];            a2[i][j]+=2*m2[i][j];        }    for(i=1;i<n;i++)        for(j=1;j<=m;j++)        {            scanf("%d",&m3[i][j]);            sum+=2*m3[i][j];            a1[i][j]+=m3[i][j];            a1[i+1][j]+=m3[i][j];            a3[i][j]+=m3[i][j];        }    for(i=1;i<n;i++)        for(j=1;j<=m;j++)        {            scanf("%d",&m4[i][j]);            sum+=2*m4[i][j];            a2[i][j]+=m4[i][j];            a2[i+1][j]+=m4[i][j];            a3[i][j]+=m4[i][j];        }    for(i=1;i<=n;i++)        for(j=1;j<m;j++)        {            scanf("%d",&m5[i][j]);            sum+=2*m5[i][j];            a1[i][j]+=m5[i][j];            a1[i][j+1]+=m5[i][j];            a4[i][j]+=m5[i][j];        }    for(i=1;i<=n;i++)        for(j=1;j<m;j++)        {            scanf("%d",&m6[i][j]);            sum+=2*m6[i][j];            a2[i][j]+=m6[i][j];            a2[i][j+1]+=m6[i][j];            a4[i][j]+=m6[i][j];        }    num=n*m+2;    S=n*m+1;    T=n*m+2;    for(i=1;i<=n;i++)        for(j=1;j<=m;j++)        {            add(S,id(i,j),a1[i][j]);            add(id(i,j),S,0);            add(id(i,j),T,a2[i][j]);            add(T,id(i,j),0);        }    for(i=1;i<n;i++)        for(j=1;j<=m;j++)        {            add(id(i,j),id(i+1,j),a3[i][j]);            add(id(i+1,j),id(i,j),a3[i][j]);        }    for(i=1;i<=n;i++)        for(j=1;j<m;j++)        {            add(id(i,j),id(i,j+1),a4[i][j]);            add(id(i,j+1),id(i,j),a4[i][j]);        }    int ans=maxflow();    ans=sum-ans;    ans>>=1;    printf("%d\n",ans);    return 0;}
原创粉丝点击