zoukankan      html  css  js  c++  java
  • BZOJ3894:文理分科——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=3894

    文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)

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

    网络流,虽然我知道一个比我下面说的要简单的做法,但是我忘了(滑稽。

    按照最小割的套路,与S有边表示选文,与T有边表示选理。

    那么S对每个人连art边权,每个人对T连sci边权。

    棘手的就是处理文科和理科之间的关系。

    考虑对每个人新建同文理点,向与其相邻的人(包括他自己)连INF的边(注意方向别反了),S向同文点连sameart边,同理点向T连samesci边。

    (自己画一画图大概就能感受到它的正确性了)

    跑一遍最大流最小割,然后用总边权减掉最大流即可。

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    const int M=N*32;
    const int INF=1e9;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int nxt,to,w;
    }edge[M];
    int head[N],cnt=-1,S,T;
    inline void add(int u,int v,int w){
        edge[++cnt].to=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt;
        edge[++cnt].to=u;edge[cnt].w=0;edge[cnt].nxt=head[v];head[v]=cnt;
    }
    int lev[N],cur[N],dui[N],a[101][101],b[101][101];
    int da[101][101],db[101][101];
    bool bfs(int m){
        int r=0;
        for(int i=1;i<=m;i++){
            lev[i]=-1;
            cur[i]=head[i];
        }
        dui[0]=S,lev[S]=0;
        int u,v;
        for(int l=0;l<=r;l++){
            u=dui[l];
            for(int e=head[u];e!=-1;e=edge[e].nxt){
                v=edge[e].to;
                if(edge[e].w>0&&lev[v]==-1){ 
                    lev[v]=lev[u]+1;
                    r++;
                    dui[r]=v; 
                    if(v==T)return 1; 
                }
            }
        }
        return 0;
    }
    int dinic(int u,int flow,int m){
        if(u==m)return flow;
        int res=0,delta;
        for(int &e=cur[u];e!=-1;e=edge[e].nxt){
            int v=edge[e].to;
            if(edge[e].w>0&&lev[u]<lev[v]){ 
                delta=dinic(v,min(edge[e].w,flow-res),m); 
                if(delta>0){
                    edge[e].w-=delta;
                    edge[e^1].w+=delta;
                    res+=delta;
                    if(res==flow)break; 
                }
            }
        }
        if(res!=flow)lev[u]=-1;
        return res;
    }
    int dx[5]={0,1,0,-1,0};
    int dy[5]={1,0,-1,0,0};
    int main(){
        memset(head,-1,sizeof(head));
        int n=read(),m=read(),ans=0;
        S=n*m*3+1,T=S+1;
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]=read();
            ans+=a[i][j];
        }
        }
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            b[i][j]=read();
            ans+=b[i][j];
        }
        }
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            da[i][j]=read();
            ans+=da[i][j];
        }
        }
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            db[i][j]=read();
            ans+=db[i][j];
        }
        }
        for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int now=(i-1)*m+j;
            add(S,now,a[i][j]);
            add(now,T,b[i][j]);
            add(S,now+n*m,da[i][j]);
            add(now+2*n*m,T,db[i][j]);
            for(int k=0;k<5;k++){
            int nx=i+dx[k],ny=j+dy[k];
            if(nx<1||nx>n||ny<1||ny>m)continue;
            int pre=(nx-1)*m+ny;
            add(now+n*m,pre,INF);
            add(pre,now+2*n*m,INF);
            }
        }
        }
        while(bfs(T))ans-=dinic(S,INF,T);
        printf("%d
    ",ans);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    利用DTrace实时检测MySQl
    改进MySQL Order By Rand()的低效率
    RDS for MySQL查询缓存 (Query Cache) 的设置和使用
    RDS For MySQL 字符集相关说明
    RDS for MySQL 通过 mysqlbinlog 查看 binlog 乱码
    RDS for MySQL Mysqldump 常见问题和处理
    RDS for MySQL Online DDL 使用
    RDS MySQL 表上 Metadata lock 的产生和处理
    RDS for MySQL 如何使用 Percona Toolkit
    北京已成为投融资诈骗重灾区:存好骗子公司黑名单,谨防上当!
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8651606.html
Copyright © 2011-2022 走看看