• BZOJ 3894: 文理分科 [最小割]


    3894: 文理分科

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 674  Solved: 392
    [Submit][Status][Discuss]

    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

    HINT

    样例说明

    1表示选择文科,0表示选择理科,方案如下:

    1  0  0  1

    0  1  0  0

    1  0  0  0
     
    N,M<=100,读入数据均<=500

    一个人要不选文,要不选理,必须放弃一个
    如果没有相邻的神秘加成,直接:
    s--文的满意值-->人--理的满意值-->t
    那么现在有神秘加成,如何把这个东西割去
    对于文科的神秘加成,建一个点连s容量为全部选文的满意值,这个点连四周的人容量INF,这样的话这个满意值和那些人选理的满意值必须有一个被割去
    理科同理
     
    点数3nm,边数2nm+2nm+10nm=14nm
     
    注意
    连四周也要连自己啊啊啊啊啊啊啊 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=3e4+5,M=2e5+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,b,c;
    struct edge{
        int v,c,f,ne;
    }e[M<<1];
    int cnt,h[N];
    inline void ins(int u,int v,int c){//printf("ins %d %d %d
    ",u,v,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;
    }
    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 ans;
    int main(){
        //freopen("in.txt","r",stdin);
        n=read();m=read();
        num=n*m;
        s=0;t=num*3+1;
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a=read(),ins(s,id(i,j),a),ans+=a;
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b=read(),ins(id(i,j),t,b),ans+=b;
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
            c=read();int k=id(i,j)+num;ans+=c;
            ins(s,k,c);
            ins(k,id(i,j),INF);
            if(i-1>=1) ins(k,id(i-1,j),INF);
            if(j+1<=m) ins(k,id(i,j+1),INF);
            if(i+1<=n) ins(k,id(i+1,j),INF);
            if(j-1>=1) ins(k,id(i,j-1),INF);
        }
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
            c=read();int k=id(i,j)+num+num;ans+=c;
            ins(k,t,c);
            ins(id(i,j),k,INF);
            if(i-1>=1) ins(id(i-1,j),k,INF);
            if(j+1<=m) ins(id(i,j+1),k,INF);
            if(i+1<=n) ins(id(i+1,j),k,INF);
            if(j-1>=1) ins(id(i,j-1),k,INF);
        }
        printf("%d",ans-dinic());
    }
  • 相关阅读:
    Codeforces Round #350 (Div. 2) F. Restore a Number 模拟
    Codeforces Round #374 (Div. 2) C. Journey DP
    Codeforces Round #375 (Div. 2) D. Lakes in Berland DFS
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 堆
    Ubuntu 安装 搜狗输入法
    Ubuntu 搜索不到WIFI或连接不上的解决方法
    Ubuntu 线缆被拔出问题
    Codeforces Round #357 (Div. 2) D. Gifts by the List DFS
    Codeforces Round #357 (Div. 2) C. Heap Operations 优先队列
    Codeforces Round #356 (Div. 2) C. Bear and Prime 100 交互题
  • 原文地址:https://www.cnblogs.com/candy99/p/6257833.html
Copyright © 2020-2023  润新知