zoukankan      html  css  js  c++  java
  • 「BZOJ2127」happiness(最小割)

    题目描述

    高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。

    作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

    输入输出格式

    输入格式:

    第一行两个正整数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列的同学同时选择理科获得的额外喜悦值。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    1 2
    1 1
    100 110
    1
    1000
    输出样例#1: 复制
    1210
    

    说明

    【样例说明】

    两人都选理,则获得100+110+1000的喜悦值。

    对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

    题解

     额,这题最重要的是一个模型转换的思想。因为最小割可以代表选择或不选择,那么我们就让每一个最小割的状态分别代表题目所示的每一个状态

      先考虑建图,假设$A$和$B$是有关联的两点,那么建如下的图

     

      其中$S$表示源点,代表文科,$T$表示汇点,代表理科,$A,B$是互相关联的两点。这张图的意思是,如果某个点与$S$相连,代表它选择文科,如果与$T$相连,代表它选择理科

      那么我们考虑一下,要怎么样才能使全文,全理,一文一理三种情况都能出现呢?

      我们考虑图中边的流量,a=A文+AB文/2,c=B文+AB文/2,b=A理+AB理/2,d=B理+AB理/2,e=f=AB文/2+AB理/2

      因为最小割的割可以代表选择,所以我们可以通过枚举割来枚举选择。那么上图中是不是每一个割都代表了一种选择呢?

      我们设sum=A文+B文+A理+B理+AB文+AB理

      当两人都选文时,我们割去b,d,那么割的大小为A理+B理+AB理,用sum减去割剩下的就是全选文的高兴值

      如果两人都选理,那么我们割去a,c,和上面一个一样,就不多说

      如果两人一文一理怎么办呢?我们假设A文B理,割去a,f,d,那么sum减去割的大小就是A选文和B选理的高兴值

      综上所述,不难发现上图的每一个割都代表了一种选择的状态。那么我们要令高兴值最大,那么割必须最小,只要求出一个最小割就行了

      代码参考(抄)了hzwer的

      1 // luogu-judger-enable-o2
      2 //minamoto
      3 #include<iostream>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<queue>
      7 #define inf 0x3f3f3f3f
      8 using namespace std;
      9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     10 char buf[1<<21],*p1=buf,*p2=buf;
     11 inline int read(){
     12     #define num ch-'0'
     13     char ch;bool flag=0;int res;
     14     while(!isdigit(ch=getc()))
     15     (ch=='-')&&(flag=true);
     16     for(res=num;isdigit(ch=getc());res=res*10+num);
     17     (flag)&&(res=-res);
     18     #undef num
     19     return res;
     20 }
     21 const int N=10005,M=500005;
     22 int head[N],Next[M],ver[M],edge[M],tot=1;
     23 int dep[N],cur[N],n,m,s,t,mxflow;
     24 int a[105][105],b[105][105],id[105][105],ans;
     25 queue<int> q;
     26 inline void add_edge(int u,int v,int e){
     27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
     28 }
     29 inline void ins(int u,int v,int e){
     30     add_edge(u,v,e),add_edge(v,u,e);
     31 }
     32 inline void insert(int u,int v,int e){
     33     add_edge(u,v,e),add_edge(v,u,0);
     34 }
     35 bool bfs(){
     36     memset(dep,-1,sizeof(dep));
     37     while(!q.empty()) q.pop();
     38     for(int i=s;i<=t;++i) cur[i]=head[i];
     39     q.push(s),dep[s]=0;
     40     while(!q.empty()){
     41         int u=q.front();q.pop();
     42         for(int i=head[u];i;i=Next[i]){
     43             int v=ver[i];
     44             if(dep[v]<0&&edge[i]){
     45                 dep[v]=dep[u]+1,q.push(v);
     46                 if(v==t) return true;
     47             }
     48         }
     49     }
     50     return false;
     51 }
     52 int dfs(int u,int limit){
     53     if(u==t||!limit) return limit;
     54     int flow=0,f;
     55     for(int i=cur[u];i;i=Next[i]){
     56         int v=ver[i];cur[u]=i;
     57         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
     58             flow+=f,limit-=f;
     59             edge[i]-=f,edge[i^1]+=f;
     60             if(!limit) break;
     61         }
     62     }
     63     if(!flow) dep[u]=-1;
     64     return flow;
     65 }
     66 void dinic(){
     67     while(bfs()) mxflow+=dfs(s,inf);
     68 }
     69 void build(){
     70     int x;s=0,t=n*m+1;
     71     for(int i=1;i<n;++i)
     72     for(int j=1;j<=m;++j){
     73         x=read(),ans+=x;
     74         a[i][j]+=x,a[i+1][j]+=x;
     75         ins(id[i][j],id[i+1][j],x);
     76     }
     77     for(int i=1;i<n;++i)
     78     for(int j=1;j<=m;++j){
     79         x=read(),ans+=x;
     80         b[i][j]+=x,b[i+1][j]+=x;
     81         ins(id[i][j],id[i+1][j],x);
     82     }
     83     for(int i=1;i<=n;++i)
     84     for(int j=1;j<m;++j){
     85         x=read(),ans+=x;
     86         a[i][j]+=x,a[i][j+1]+=x;
     87         ins(id[i][j],id[i][j+1],x);
     88     }
     89     for(int i=1;i<=n;++i)
     90     for(int j=1;j<m;++j){
     91         x=read(),ans+=x;
     92         b[i][j]+=x,b[i][j+1]+=x;
     93         ins(id[i][j],id[i][j+1],x);
     94     }
     95     for(int i=1;i<=n;++i)
     96     for(int j=1;j<=m;++j){
     97         insert(s,id[i][j],a[i][j]);
     98         insert(id[i][j],t,b[i][j]);
     99     }
    100 }
    101 int main(){
    102     //freopen("testdata.in","r",stdin);
    103     n=read(),m=read();
    104     for(int i=1;i<=n;++i)
    105     for(int j=1;j<=m;++j)
    106     a[i][j]=read(),ans+=a[i][j],a[i][j]<<=1;
    107     for(int i=1;i<=n;++i)
    108     for(int j=1;j<=m;++j)
    109     b[i][j]=read(),ans+=b[i][j],b[i][j]<<=1;
    110     for(int i=1;i<=n;++i)
    111     for(int j=1;j<=m;++j)
    112     id[i][j]=(i-1)*m+j;
    113     build(),dinic();
    114     printf("%d
    ",ans-(mxflow>>1));
    115     return 0;
    116 }
  • 相关阅读:
    vim符号列表
    vim树形目录
    用java实现二叉树的遍历算法
    Java 泛型
    Java简单实用代码分享,这里一定有你想要的!
    Java对象大小的计算方式
    JavaScript 类型转换
    只需亿小串代码,教你用java仿制qq
    软帝学院教你HTMLDOM是什么
    MySQL 教程
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9568462.html
Copyright © 2011-2022 走看看