zoukankan      html  css  js  c++  java
  • 【BZOJ】【2127】happiness

    网络流/最小割


      Orz Hzwer

      这题他题解说的比较简略……我手画了个图才明白过来……

      嗯对于每个人选文or理的单独收益大家应该很好理解……连S->i 权值为选文的喜悦值,i->T权值为选理的喜悦值,然后所有的加起来减去最小割即可。

      那么有了相邻的额外喜悦值怎么办呢?首先它跟之前的问题没有冲突,完全可以叠加来做。如上图考虑额外喜悦值,tot=w1+w2,那么我们能得到的最大喜悦值就是tot-最小割,如果我们是两个人选了相同的一科,那割掉的边必然是左边的两条(和为w1)或是右边的两条(和为w2),那如果是选了不同的两科,割掉的就是对角线上的三条边(和为w1+w2),显而易见,这样就可以利用【最小割】来求出最大的喜悦值了。

      这道题我遇到了一个神奇的情况……我跟Hzwer都是写的Dinic,但是我跑下来就有15000ms+,他的程序只有1400ms+,速度是我的十倍啊……

      后来我各种修改然后发现:我加了当前弧优化!这个题目中实际上每个点的边数并不多,所以当前弧优化并不明显,但是每次重建残量网络的时候都要重新初始化一遍当前弧数组cur,这带来了大量的时间浪费……所以就华丽丽地……还好没超时。

      所以对于稀疏图还是不要用当前弧优化了= =尤其是在增广次数比较多的时候……

      1 /**************************************************************
      2     Problem: 2127
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:15184 ms
      7     Memory:6232 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 2127
     11 #include<vector>
     12 #include<cstdio>
     13 #include<cstring>
     14 #include<cstdlib>
     15 #include<iostream>
     16 #include<algorithm>
     17 #define rep(i,n) for(int i=0;i<n;++i)
     18 #define F(i,j,n) for(int i=j;i<=n;++i)
     19 #define D(i,j,n) for(int i=j;i>=n;--i)
     20 #define pb push_back
     21 using namespace std;
     22 inline int getint(){
     23     int v=0,sign=1; char ch=getchar();
     24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     26     return v*sign;
     27 }
     28 const int N=11000,M=300000,INF=~0u>>2;
     29 typedef long long LL;
     30 /******************tamplate*********************/
     31 int n,m,ans,tot,a[110][110],b[110][110];
     32 struct edge{
     33     int from,to,v;
     34 };
     35 inline int pack(int i,int j){return (i-1)*m+j;}
     36 struct Net{
     37     edge E[M];
     38     int head[N],next[M],cnt;
     39     void add(int x,int y,int v){
     40         E[++cnt]=(edge){x,y,v};
     41         next[cnt]=head[x]; head[x]=cnt;
     42         E[++cnt]=(edge){y,x,0};
     43         next[cnt]=head[y]; head[y]=cnt;
     44     }
     45     void add2(int x,int y,int v){
     46         E[++cnt]=(edge){x,y,v};
     47         next[cnt]=head[x]; head[x]=cnt;
     48         E[++cnt]=(edge){y,x,v};
     49         next[cnt]=head[y]; head[y]=cnt;
     50     }
     51     int s,t,cur[N],d[N],Q[N];
     52     void init(){
     53         n=getint();m=getint();
     54         ans=tot=0;cnt=1;
     55         s=0; t=n*m+1;
     56         F(i,1,n) F(j,1,m){
     57             a[i][j]=getint();
     58             tot+=a[i][j]; a[i][j]<<=1;
     59         }
     60         F(i,1,n) F(j,1,m){
     61             b[i][j]=getint();
     62             tot+=b[i][j]; b[i][j]<<=1;
     63         }
     64         int x;
     65         F(i,1,n-1) F(j,1,m){
     66             x=getint(); tot+=x;
     67             a[i][j]+=x; a[i+1][j]+=x;
     68             add2(pack(i,j),pack(i+1,j),x);
     69         }
     70         F(i,1,n-1) F(j,1,m){
     71             x=getint(); tot+=x;
     72             b[i][j]+=x; b[i+1][j]+=x;
     73             add2(pack(i,j),pack(i+1,j),x);
     74         }
     75         F(i,1,n) F(j,1,m-1){
     76             x=getint(); tot+=x;
     77             a[i][j]+=x; a[i][j+1]+=x;
     78             add2(pack(i,j),pack(i,j+1),x);
     79         }
     80         F(i,1,n) F(j,1,m-1){
     81             x=getint(); tot+=x;
     82             b[i][j]+=x; b[i][j+1]+=x;
     83             add2(pack(i,j),pack(i,j+1),x);
     84         }
     85         F(i,1,n) F(j,1,m){
     86             add(s,pack(i,j),a[i][j]);
     87             add(pack(i,j),t,b[i][j]);
     88         }
     89     }
     90     bool mklevel(){
     91         memset(d,-1,sizeof d);
     92         d[s]=0;
     93         int l=0,r=-1;
     94         Q[++r]=s;
     95         while(l<=r){
     96             int x=Q[l++];
     97             for(int i=head[x];i;i=next[i])
     98                 if (d[E[i].to]==-1 && E[i].v){
     99                     d[E[i].to]=d[x]+1;
    100                     Q[++r]=E[i].to;
    101                 }
    102         }
    103         return d[t]!=-1;
    104     }
    105     int dfs(int x,int a){
    106         if (x==t||a==0) return a;
    107         int flow=0;
    108         for(int &i=cur[x];i && flow<a;i=next[i])
    109             if (d[E[i].to]==d[x]+1 && E[i].v){
    110                 int f=dfs(E[i].to,min(a-flow,E[i].v));
    111                 E[i].v-=f;
    112                 E[i^1].v+=f;
    113                 flow+=f;
    114             }
    115         return flow;
    116     }
    117     int Dinic(){
    118         int flow=0;
    119         while(mklevel()){
    120             F(i,s,t) cur[i]=head[i];
    121             flow+=dfs(s,INF);
    122         }
    123         return flow;
    124     }
    125 }G1;
    126 int main(){
    127 #ifndef ONLINE_JUDGE
    128     freopen("2127.in","r",stdin);
    129     freopen("2127.out","w",stdout);
    130 #endif
    131     G1.init();
    132     printf("%d
    ",tot-(G1.Dinic()>>1));
    133     return 0;
    134 }
    View Code 时间超长……
      1 /**************************************************************
      2     Problem: 2127
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:1332 ms
      7     Memory:4600 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 2127
     11 #include<cstdio>
     12 #include<cstring>
     13 #include<algorithm>
     14 #define rep(n,m) for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
     15 #define FOR for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
     16 using namespace std;
     17 inline int getint(){
     18     int v=0,sign=1; char ch=getchar();
     19     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     20     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     21     return v*sign;
     22 }
     23 const int N=10005,M=300000,INF=~0u>>2;
     24 typedef long long LL;
     25 /******************tamplate*********************/
     26 int n,m,ans,tot,a[101][101],b[101][101],pack[101][101];
     27 struct edge{
     28     int to,v;
     29 };
     30 edge E[M];
     31 int head[N],next[M],cnt;
     32 void ins(int x,int y,int v){
     33     ++cnt; E[cnt].to=y; E[cnt].v=v;
     34     next[cnt]=head[x]; head[x]=cnt;
     35 }
     36 void add(int x,int y,int v){
     37     ins(x,y,v); ins(y,x,0);
     38 }
     39 void add2(int x,int y,int v){
     40     ins(x,y,v); ins(y,x,v);
     41 }
     42 int s,t,cur[N],d[N],Q[N];
     43 void init(){
     44     n=getint();m=getint();
     45     ans=tot=0;cnt=1;
     46     s=0; t=n*m+1;
     47     FOR a[i][j]=getint(),tot+=a[i][j],a[i][j]<<=1;
     48     FOR b[i][j]=getint(),tot+=b[i][j],b[i][j]<<=1;
     49     FOR pack[i][j]=(i-1)*m+j;
     50     int x;
     51     rep(n-1,m){
     52         x=getint(); tot+=x;
     53         a[i][j]+=x; a[i+1][j]+=x;
     54         add2(pack[i][j],pack[i+1][j],x);
     55     }
     56     rep(n-1,m){
     57         x=getint(); tot+=x;
     58         b[i][j]+=x; b[i+1][j]+=x;
     59         add2(pack[i][j],pack[i+1][j],x);
     60     }
     61     rep(n,m-1){
     62         x=getint(); tot+=x;
     63         a[i][j]+=x; a[i][j+1]+=x;
     64         add2(pack[i][j],pack[i][j+1],x);
     65     }
     66     rep(n,m-1){
     67         x=getint(); tot+=x;
     68         b[i][j]+=x; b[i][j+1]+=x;
     69         add2(pack[i][j],pack[i][j+1],x);
     70     }
     71     FOR{
     72         add(s,pack[i][j],a[i][j]);
     73         add(pack[i][j],t,b[i][j]);
     74     }
     75 }
     76 bool mklevel(){
     77     memset(d,-1,sizeof d);
     78     d[s]=0;
     79     int l=0,r=-1;
     80     Q[++r]=s;
     81     while(l<=r){
     82         int x=Q[l++];
     83         for(int i=head[x];i;i=next[i])
     84             if (d[E[i].to]==-1 && E[i].v){
     85                 d[E[i].to]=d[x]+1;
     86                 Q[++r]=E[i].to;
     87             }
     88     }
     89     return d[t]!=-1;
     90 }
     91 int dfs(int x,int a){
     92     if (x==t||a==0) return a;
     93     int flow=0;
     94     for(int i=head[x];i && flow<a;i=next[i])
     95         if (d[E[i].to]==d[x]+1 && E[i].v){
     96             int f=dfs(E[i].to,min(a-flow,E[i].v));
     97             E[i].v-=f;
     98             E[i^1].v+=f;
     99             flow+=f;
    100         }
    101     if (!flow) d[x]=-1;
    102     return flow;
    103 }
    104 void Dinic(){
    105     while(mklevel()) ans+=dfs(s,INF);
    106 }
    107 int main(){
    108 #ifndef ONLINE_JUDGE
    109     freopen("2127.in","r",stdin);
    110     freopen("2127.out","w",stdout);
    111 #endif
    112     init(); Dinic();
    113     printf("%d
    ",tot-(ans>>1));
    114     return 0;
    115 }
    116 
    View Code 速度超快~

    2127: happiness

    Time Limit: 51 Sec  Memory Limit: 259 MB
    Submit: 923  Solved: 444
    [Submit][Status][Discuss]

    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

    [Submit][Status][Discuss]
  • 相关阅读:
    DROP,TRUNCATE 和DELETE的区别
    工作手记之Cransoft
    Java输入输出流
    上海植物园
    eclipse中开发android程序时,打开layout配置文件eclipse关闭
    Android SDK 2.2 开发环境搭建
    Android读取电话薄中的电话号码
    Android模拟器大小
    工作手记之Cransoft(二)
    工作手记之Cransoft(三)
  • 原文地址:https://www.cnblogs.com/Tunix/p/4338011.html
Copyright © 2011-2022 走看看