zoukankan      html  css  js  c++  java
  • BZOJ2127: happiness

    2127: happiness

    Time Limit: 51 Sec  Memory Limit: 259 MB
    Submit: 605  Solved: 283
    [Submit][Status]

    Description

    高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

    Input

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

    Output

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

    Sample Input

    1 2
    1 1
    100 110
    1
    1000

    Sample Output

    1210
    【样例说明】
    两人都选理,则获得100+110+1000的喜悦值。
    【数据规模】
    对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

    HINT

     

    Source

    题解:

    就算是我懂了。。。

    搬运题解:

    首先发现题目出现了很明显的二分图关系--选文科还是理科,很明显是一个网络流问题,联系到题目上的一个人选文科还是理科可以得到一定喜悦值,两个人同时选文科还是理科,又可以得到一定喜悦值,发现最终答案是由每个人选文科,还是选理科,这个行为确定的,与最小割有一定关系。

         继续观察,如果按最小割建立模型,每个人选文选理的代价可以在与s,t的连边上体现,这时难点就变成了如何体现两个人之间的关系:同时选文或选理需要的代价。

       这时引入一个很神奇的东西,无向边。

       这个东西是我在clj的ppt上看见的,有一个很有用的作用:若A<-->B:C,即A与B连一条权值为C的无向边,当这条无向边计入最小割时,表示这两个点分属于s,t两个集合。

       但是仅仅知道如此是不够的,因为对于A,B两点,如果他们都属于S集合,即与T集合的边已经计入最小割了,那A与B之间的边就一定不会出现在最小割里,这一点可以作图验证一二。

       所以我们应该对原图进行一定变换。注意到这里我们是想将两个点之间的关系体现在同时取s集或同时取t集的情况,即与s,与t的连接边:若A与B同时选文得到W1的喜悦值,同时选理得到W2的喜悦值,S->A:w1/2,A->T:w2/2,

    S->B:w1/2,B->T:w2/2,A<-->B:(w1+w2)/2。

       为什么呢?自己画图验证,很神奇的东西,特别难想,不过做过一遍以后再做就觉得很容易了。

    似乎从最小割的含义来考虑是显然的?毕竟我还太弱。。。

    代码:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cmath>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<iostream>
      7 #include<vector>
      8 #include<map>
      9 #include<set>
     10 #include<queue>
     11 #include<string>
     12 #define inf 1000000000
     13 #define maxn 100000
     14 #define maxm 500000
     15 #define eps 1e-10
     16 #define ll long long
     17 #define pa pair<int,int>
     18 #define rep(x,y) for(int i=1;i<=x;i++)for(int j=1;j<=y;j++)
     19 #define FOR for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
     20 #define mod 1000000007
     21 using namespace std;
     22 inline int read()
     23 {
     24     int x=0,f=1;char ch=getchar();
     25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
     27     return x*f;
     28 }
     29 int  n,m,s,t,maxflow,cnt=1,tot,a[105][105],b[105][105],mark[105][105],head[maxn],cur[maxn],h[maxn],q[maxn];
     30 struct edge{int go,next,v;}e[maxm];
     31 void ins(int x,int y,int z){e[++cnt].go=y;e[cnt].v=z;e[cnt].next=head[x];head[x]=cnt;}
     32 void insert(int x,int y,int z){ins(x,y,z);ins(y,x,0);}
     33 void ins2(int x,int y,int z){insert(x,y,z);insert(y,x,z);}
     34 bool bfs()
     35 {
     36     for(int i=s;i<=t;i++)h[i]=-1;
     37     int l=0,r=1;q[1]=s;h[s]=0;
     38     while(l<r)
     39     {
     40         int x=q[++l];
     41         for(int i=head[x];i;i=e[i].next)
     42          if(e[i].v&&h[e[i].go]==-1)
     43          {
     44             h[e[i].go]=h[x]+1;q[++r]=e[i].go;
     45          }
     46     }
     47     return h[t]!=-1;
     48 }
     49 int dfs(int x,int f)
     50 {
     51     if(x==t) return f;
     52     int tmp,used=0;
     53     for(int i=head[x];i;i=e[i].next)
     54      if(e[i].v&&h[e[i].go]==h[x]+1)
     55     {
     56         tmp=dfs(e[i].go,min(e[i].v,f-used));
     57         e[i].v-=tmp;if(e[i].v)cur[x]=i;
     58         e[i^1].v+=tmp;used+=tmp;
     59         if(used==f)return f;       
     60     }
     61     if(!used) h[x]=-1;
     62     return used;
     63 }
     64 void dinic()
     65 {
     66     maxflow=0;
     67     while(bfs())
     68     {
     69         for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf);
     70     }
     71 }
     72 int main()
     73 {
     74     freopen("input.txt","r",stdin);
     75     freopen("output.txt","w",stdout);
     76     n=read();m=read();
     77     FOR a[i][j]=read(),tot+=a[i][j],a[i][j]<<=1;
     78     FOR b[i][j]=read(),tot+=b[i][j],b[i][j]<<=1;
     79     FOR mark[i][j]=(i-1)*m+j;
     80     s=0;t=mark[n][m]+1;
     81     int x;
     82     rep(n-1,m)
     83     {
     84        x=read();tot+=x;
     85        a[i][j]+=x;a[i+1][j]+=x;
     86        ins2(mark[i][j],mark[i+1][j],x);
     87     }
     88     rep(n-1,m)
     89     {
     90        x=read();tot+=x;
     91        b[i][j]+=x;b[i+1][j]+=x;
     92        ins2(mark[i][j],mark[i+1][j],x);
     93     }
     94     rep(n,m-1)
     95     {
     96        x=read();tot+=x;
     97        a[i][j]+=x;a[i][j+1]+=x;
     98        ins2(mark[i][j],mark[i][j+1],x);
     99     }
    100     rep(n,m-1)
    101     {
    102        x=read();tot+=x;
    103        b[i][j]+=x;b[i][j+1]+=x;
    104        ins2(mark[i][j],mark[i][j+1],x);
    105     }
    106     FOR{
    107            insert(s,mark[i][j],a[i][j]);
    108            insert(mark[i][j],t,b[i][j]);
    109        }
    110     dinic();
    111     printf("%d
    ",tot-(maxflow>>1));
    112     return 0;
    113 }
    View Code

     UPD:

    写了下另一种解法:

    考虑同桌同选文科的额外收获w,

    我们新建一个节点x,连边s-> 容量为w,

    x到u,v容量为inf。

    当w算入割的时候u,v都属于t割,即选了文科。

    这种方法新建了很多新点,虽然速度慢,但是好理解。

    代码:

      1 #include<cstdio>
      2 
      3 #include<cstdlib>
      4 
      5 #include<cmath>
      6 
      7 #include<cstring>
      8 
      9 #include<algorithm>
     10 
     11 #include<iostream>
     12 
     13 #include<vector>
     14 
     15 #include<map>
     16 
     17 #include<set>
     18 
     19 #include<queue>
     20 
     21 #include<string>
     22 
     23 #define inf 1000000000
     24 
     25 #define maxn 200000+5
     26 
     27 #define maxm 500000+5
     28 
     29 #define eps 1e-10
     30 
     31 #define ll long long
     32 
     33 #define pa pair<int,int>
     34 
     35 #define for0(i,n) for(int i=0;i<=(n);i++)
     36 
     37 #define for1(i,n) for(int i=1;i<=(n);i++)
     38 
     39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
     40 
     41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
     42 
     43 #define for4(i,x) for(int i=head[x],y;i;i=e[i].next)
     44 #define for5(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
     45 
     46 #define mod 1000000007
     47 
     48 using namespace std;
     49 int  n,m,s,t,cnt,sum,maxflow,tot=1,head[maxn],cur[maxn],h[maxn],num[150][150];
     50 queue<int>q;
     51 struct edge{int go,next,v;}e[maxm];
     52 
     53 inline int read()
     54 
     55 {
     56 
     57     int x=0,f=1;char ch=getchar();
     58 
     59     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     60 
     61     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
     62     sum+=x*f;
     63 
     64     return x*f;
     65 
     66 }
     67 inline void add(int x,int y,int v)
     68 {
     69     e[++tot]=(edge){y,head[x],v};head[x]=tot;
     70     e[++tot]=(edge){x,head[y],0};head[y]=tot;
     71 }
     72 bool bfs()
     73 {
     74     for(int i=s;i<=t;i++)h[i]=-1;
     75     q.push(s);h[s]=0;
     76     while(!q.empty())
     77     {
     78         int x=q.front();q.pop();
     79         for(int i=head[x];i;i=e[i].next)
     80          if(e[i].v&&h[e[i].go]==-1)
     81          {
     82             h[e[i].go]=h[x]+1;q.push(e[i].go);
     83          }
     84     }
     85     return h[t]!=-1;
     86 }
     87 int dfs(int x,int f)
     88 {
     89     if(x==t) return f;
     90     int tmp,used=0;
     91     for(int i=cur[x];i;i=e[i].next)
     92      if(e[i].v&&h[e[i].go]==h[x]+1)
     93     {
     94         tmp=dfs(e[i].go,min(e[i].v,f-used));
     95         e[i].v-=tmp;if(e[i].v)cur[x]=i;
     96         e[i^1].v+=tmp;used+=tmp;
     97         if(used==f)return f;       
     98     }
     99     if(!used) h[x]=-1;
    100     return used;
    101 }
    102 void dinic()
    103 {
    104     maxflow=0;
    105     while(bfs())
    106     {
    107         for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf);
    108     }
    109 }
    110 
    111 int main()
    112 
    113 {
    114 
    115     freopen("input.txt","r",stdin);
    116 
    117     freopen("output.txt","w",stdout);
    118 
    119     n=read();m=read();sum=0;s=0;t=5*n*m+1;
    120     for5(n,m)num[i][j]=(i-1)*m+j;cnt=num[n][m];
    121     for5(n,m)add(s,num[i][j],read());
    122     for5(n,m)add(num[i][j],t,read());
    123     for5(n-1,m)
    124     {
    125         add(s,++cnt,read());
    126         add(cnt,num[i][j],inf);
    127         add(cnt,num[i+1][j],inf);
    128     }
    129     for5(n-1,m)
    130     {
    131         add(++cnt,t,read());
    132         add(num[i][j],cnt,inf);
    133         add(num[i+1][j],cnt,inf);
    134     }
    135     for5(n,m-1)
    136     {
    137         add(s,++cnt,read());
    138         add(cnt,num[i][j],inf);
    139         add(cnt,num[i][j+1],inf);
    140     }
    141     for5(n,m-1)
    142     {
    143         add(++cnt,t,read());
    144         add(num[i][j],cnt,inf);
    145         add(num[i][j+1],cnt,inf);
    146     }
    147     dinic();
    148     printf("%d
    ",sum-maxflow);
    149 
    150     return 0;
    151 
    152 }  
    View Code
  • 相关阅读:
    js保留两位小数
    js字符串转成数字的三种方法
    『MySQL』索引类型 normal, unique, full text
    checkstyle配置文件说明
    如何更好地利用Pmd、Findbugs和CheckStyle分析结果
    Hibernate SQL优化技巧dynamic-insert="true" dynamic-update="true"
    Struts2 action的单例与多例
    Eclipse插件checkstyle安装使用
    html 动态显示元素文本
    脱离 Spring 实现复杂嵌套事务,之一(必要的概念)
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/4033290.html
Copyright © 2011-2022 走看看