BZOJ 2127: happiness [最小割]

2127: happiness

Time Limit: 51 Sec  Memory Limit: 259 MB
Submit: 1815  Solved: 878
[Submit][Status][Discuss]

Description

高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000

Sample Output

1210
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

本题和上一题很相似,可以用相同的做法
但是本题可以优化
相邻两个人具有经典的棋盘黑白染色的特征,虽然本题貌似与二分图无关,这是句废话
能不能在一人一点的基础上直接处理出神秘加成
放弃文同时也是放弃了 神秘加成_文/2
两个人都放弃文就成功的放弃了整个 神秘加成_文
理同理
但是一人选文一人选理两个神秘加成都不能要啊,但这样每个神秘加成只放弃了1/2
那就再加两条边,链接相邻两个人,容量为(神秘加成_文+神秘加成_理)/2,割的时候一文一理时必定割去这条两条边之一
 
提示:
那两条边可以直接加无向边
注意:
煞笔Candy?数组开成[10005][10005] bzoj不是T就是M
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e4+5,M=1e5+5,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}

int n,m,num,s,t,a[105][105],b[105][105],c,f[105][105],g[105][105],sum;
struct edge{
    int v,c,f,ne;
}e[M<<1];
int cnt,h[N];
inline void ins(int u,int v,int c){
    cnt++;
    e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt;
}
inline void ins2(int u,int v,int c){
    cnt++;
    e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt;
}
int q[N],head,tail,vis[N],d[N];
bool bfs(){
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    head=tail=1;
    d[s]=0;vis[s]=1;
    q[tail++]=s;
    while(head!=tail){
        int u=q[head++];
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(!vis[v]&&e[i].c>e[i].f){
                vis[v]=1;
                d[v]=d[u]+1;
                q[tail++]=v;
                if(v==t) return true;
            }
        }
    }
    return false;
}
int cur[N];
int dfs(int u,int a){
    if(u==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[u];i;i=e[i].ne){
        int v=e[i].v;
        if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){
            flow+=f;
            e[i].f+=f;
            e[((i-1)^1)+1].f-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int dinic(){
    int flow=0;
    while(bfs()){
        for(int i=s;i<=t;i++) cur[i]=h[i];
        flow+=dfs(s,INF);
    }
    return flow;
}
inline int id(int i,int j){return (i-1)*m+j;}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();
    s=0;t=n*m+1;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read()<<1,sum+=a[i][j]>>1;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[i][j]=read()<<1,sum+=b[i][j]>>1;
    for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++){
        c=read();a[i][j]+=c;a[i+1][j]+=c;sum+=c;
        f[i][j]+=c;
        //ins2(id(i,j),id(i+1,j),c);
    }
    for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++){
        c=read();b[i][j]+=c;b[i+1][j]+=c;sum+=c;
        f[i][j]+=c;
        //ins2(id(i,j),id(i+1,j),c);
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){
        c=read();a[i][j]+=c;a[i][j+1]+=c;sum+=c;
        g[i][j]+=c;
        //ins2(id(i,j),id(i,j+1),c);
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){
        c=read();b[i][j]+=c;b[i][j+1]+=c;sum+=c;
        g[i][j]+=c;
        //ins2(id(i,j),id(i,j+1),c);
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
        ins(s,id(i,j),a[i][j]);
        ins(id(i,j),t,b[i][j]);
        ins2(id(i,j),id(i+1,j),f[i][j]);
        ins2(id(i,j),id(i,j+1),g[i][j]);
    }
    int ans=dinic();
    printf("%d",sum-(ans>>1));
}

 

 
 
 
posted @ 2017-01-07 09:13  Candy?  阅读(289)  评论(0编辑  收藏  举报