• 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/+

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

  • 相关阅读:
    getWritableDatabase()与getReadableDatabase()方法
    使用drawBitmapMesh扭曲图像
    移动游戏背景
    使用Matrix控制图片和组件的变化
    使用Matrix控制图像或组件变换的步骤
    1105: 零起点学算法12——求2个日期之间的天数
    1104: 零起点学算法11——求梯形面积
    1103: 零起点学算法10——求圆柱体的表面积
    1102: 零起点学算法09——继续练习简单的输入和计算(a-b)
    1101: 零起点学算法08——简单的输入和计算(a+b)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8651606.html
Copyright © 2020-2023  润新知