[BZOJ2127]happiness-[网络流-最小割]

Description

传送门

Solution

按照最小割的思路考虑。

根据题意,当两个人都选文(理),需要砍掉两个人都选理(文)的加成;如果两个人选的不一样,就要都砍掉。

这是一个网络流建模的套路:

如图。为了防止出现分数,我们把每条边边权*2。

最后用总的喜悦值去掉网络流大小即可。(记得除以2)

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int inf=1e9;

int h[10020],tot=0;
struct pas{int x,y,nxt,w,op,cost;}g[300100];
int dep[10020],S,T;
queue<int>q;
struct DINIC{
bool bfs()
{
    int x;
    memset(dep,0,sizeof(dep));dep[S]=1;
    while (!q.empty()) q.pop();
    q.push(S);
    while (!q.empty())
    {
        x=q.front();q.pop();
        for (int i=h[x];i;i=g[i].nxt)
        if (!dep[g[i].y]&&g[i].w)
        {
            dep[g[i].y]=dep[x]+1;
            q.push(g[i].y);
            if (g[i].y==T) return 1;
        }
    }
    return 0;
}
int dfs(int x,int flow)
{
    if (x==T||(!flow))return flow;
    int temp=0,js;
    for (int i=h[x];i;i=g[i].nxt)
    if (dep[g[i].y]==dep[x]+1&&g[i].w)
    {
        js=dfs(g[i].y,min(flow,g[i].w));
        if (js)
        {
            g[i].w-=js;
            g[g[i].op].w+=js;
            temp+=js;
            flow-=js;
            if (!flow) return temp;
        }
    }
    if (!temp) dep[x]=0;
    return temp;
}
    int dinic()
    {
        int ans=0;
        while (bfs()) 
        ans+=dfs(S,inf);
        return ans;
    } 
 }D;
  
void add(int x,int y,int w)
{
    g[++tot].x=x;g[tot].y=y;g[tot].w=w;g[tot].nxt=h[x];g[tot].op=tot+1;h[x]=tot;
    g[++tot].x=y;g[tot].y=x;g[tot].w=0;g[tot].nxt=h[y];g[tot].op=tot-1;h[y]=tot;
}

int n,m,sum;
int art[110][110],sci[110][110];
int row_art[110][110],row_sci[110][110];
int col_art[110][110],col_sci[110][110];//col-column
int id(int x,int y){return (x-1)*m+y;}
int main()
{
    scanf("%d%d",&n,&m);
    S=0;T=id(n,m)+1;
    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
    {
        scanf("%d",&art[i][j]);    sum+=art[i][j];
        art[i][j]*=2;
    }
    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
    {
        scanf("%d",&sci[i][j]);    sum+=sci[i][j];
        sci[i][j]*=2;    
    }
    for (int i=1;i<n;i++) for (int j=1;j<=m;j++)
    {
        scanf("%d",&row_art[i][j]);sum+=row_art[i][j];    
        art[i][j]+=row_art[i][j];
        art[i+1][j]+=row_art[i][j];
    }
    for (int i=1;i<n;i++) for (int j=1;j<=m;j++)
    {
        scanf("%d",&row_sci[i][j]);sum+=row_sci[i][j];
        sci[i][j]+=row_sci[i][j];
        sci[i+1][j]+=row_sci[i][j];
        add(id(i,j),id(i+1,j),row_art[i][j]+row_sci[i][j]);
        add(id(i+1,j),id(i,j),row_art[i][j]+row_sci[i][j]);
    }
    for (int i=1;i<=n;i++) for (int j=1;j<m;j++)
    {
        scanf("%d",&col_art[i][j]);sum+=col_art[i][j];    
        art[i][j]+=col_art[i][j];
        art[i][j+1]+=col_art[i][j];        
    }
    for (int i=1;i<=n;i++) for (int j=1;j<m;j++)
    {
        scanf("%d",&col_sci[i][j]);sum+=col_sci[i][j];    
        sci[i][j]+=col_sci[i][j];
        sci[i][j+1]+=col_sci[i][j];    
        add(id(i,j),id(i,j+1),col_art[i][j]+col_sci[i][j]);
        add(id(i,j+1),id(i,j),col_art[i][j]+col_sci[i][j]);
    }
    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
    {
        add(S,id(i,j),art[i][j]);
        add(id(i,j),T,sci[i][j]);
    }
    printf("%d",(sum*2-D.dinic())/2);
}

 

posted @ 2018-08-31 11:28  _雨后阳光  阅读(141)  评论(0编辑  收藏  举报