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

    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
     
    这不全的题目描述是SMG。
    先把收益都加进来,然后想办法最小割建模。
    我们设S割的节点表示选文,T割的节点表示选理。所以对于每个点x,从S到x连一条容量为art的边,从x到T连一条容量为science的边。
    不难发现,如果想要满足一个对x而言的same_art条件,x及与x相邻的节点都不能属于T割,所以可以新建一个节点q,从S到q连一条容量为same_art的边,并从q向x及与x相邻的节点连上一条容量为inf的边。
    same_science条件同理。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=30010;
    const int maxm=1000010;
    const int inf=1e9;
    struct ISAP{
        struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn];
        int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top;
        void init(int n){
            this->n=n;ms=0;top=0;
            memset(d,-1,sizeof(d));
            memset(fch,-1,sizeof(fch));
            return;
        }
        void AddEdge(int u,int v,int w){
            adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++;
            adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++;
            return;
        }
        void bfs(){
            queue<int>Q;Q.push(n);d[n]=0;
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=fch[u];i!=-1;i=adj[i].next){
                    int v=adj[i].y;
                    if(d[v]==-1) d[v]=d[u]+1,Q.push(v);
                }
            } return;
        }
        int solve(int S,int T){
            n=T;bfs();int k=S,i,flow=0;
            for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++;
            while(d[S]<n){
                if(k==n){
                    int mi=inf,pos;
                    for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i;
                    for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi;
                    flow+=mi;top=pos;k=adj[s[top]].x;
                }
                for(i=cur[k];i!=-1;i=adj[i].next){
                    int v=adj[i].y;
                    if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;}
                }
                if(i==-1){
                    int lim=n;
                    for(i=fch[k];i!=-1;i=adj[i].next){
                        int v=adj[i].y;
                        if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i;
                    } if(--gap[d[k]]==0) break;
                    d[k]=lim+1;gap[d[k]]++;
                    if(k!=S) k=adj[s[--top]].x;
                }
            } return flow;
        }
    }sol;
    int n,m,sum,v;
    int id(int x,int y,int t) {return t*n*m+(x-1)*m+y;}
    const int mx[]={0,1,-1,0,0};
    const int my[]={0,0,0,1,-1};
    int main() {
        n=read(),m=read();
    	int S=n*m*3+1,T=n*m*3+2;sol.init(T);
        rep(i,1,n) rep(j,1,m) sol.AddEdge(S,id(i,j,0),v=read()),sum+=v;
        rep(i,1,n) rep(j,1,m) sol.AddEdge(id(i,j,0),T,v=read()),sum+=v;
        rep(i,1,n) rep(j,1,m) {
    		sol.AddEdge(S,id(i,j,1),v=read());sum+=v;
    		rep(dir,0,4) {
    			int nx=i+mx[dir],ny=j+my[dir];
    			if(nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(i,j,1),id(nx,ny,0),inf);
    		}
    	}
    	rep(i,1,n) rep(j,1,m) {
    		sol.AddEdge(id(i,j,2),T,v=read());sum+=v;
    		rep(dir,0,4) {
    			int nx=i+mx[dir],ny=j+my[dir];
    			if(nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(nx,ny,0),id(i,j,2),inf);
    		}
    	}
    	printf("%d
    ",sum-sol.solve(S,T));
        return 0;
    }
    

      

  • 相关阅读:
    Linux下将pycharm图标添加至桌面
    在linux命令下如何访问一个url?
    sudo 出现unable to resolve host 解决方法
    时间处理插件moment.js
    vue视图不更新情况详解
    基于webstorm卡顿问题的2种解决方法
    Windows10内置Linux子系统
    VUE项目中使用this.$forceUpdate();解决页面v-for中修改item属性值后页面v-if不改变的问题
    vue $forceUpdate() 强制重新渲染
    Vue 实现手动刷新组件
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5316681.html
Copyright © 2011-2022 走看看