zoukankan      html  css  js  c++  java
  • [BZOJ2127]happiness

    题目大意:
    有一个$n imes m$的阵列,每个位置上有一元素,现在要将这些元素分为$A$部和$B$部,
    对于每个元素$i$,如果它被分到了$A$部,就会得到相应的收益$a_i$;如果它被分到了$B$部,也会得到相应的收益$b_i$。
    对于每两个相邻的元素$i$和$j$,如果被同时分在$A$部或$B$部,也会有相应的额外收益$c_{ij}$,$d_{ij}$。

    思路:
    考虑最小割将所有元素分$S$集和$T$集,$S$集表示$A$部,$T$集表示$B$部,
    对于每个元素$i$,连一条从$S$到$i$的容量为$a_i$的边,再连一条从$i$到$T$的容量为$b_i$的边,若其中一条被割去,则说明该元素不在那个集合,易证在最小割中,这两条边有且仅有一条会被割去。
    对于每两个相邻的元素$i$和$j$,设$flow(x,y)$表示下面新加入的边的容量,分以下三种情况考虑:
      1.两个元素都被分在了$A$部,那么两人加入$B$部得到的收益应当被加入到割集中,除了割去原有的边以外,还需要割去两个元素共同加入$B$集的收益,因此只要增加满足$flow(i,T)+flow(j,T)=c_{ij}$的边即可。
      2.两个元素都被分在了$B$部,同上得$flow(S,i)+flow(S,j)=d_{ij}$。
      3.两个元素属于不同集合,假设$i$属于$A$部,$j$属于$B$部,那么我们可以发现,两者都属于$A$部或$B$部的额外收益都得被割掉,因此我们需要保证新加入的边$flow(S,i)+flow(i,j)+flow(j,T)=c_{ij}+d_{ij}$。同理,若$j$属$A$部,$i$属$B$部,则需要保证$flow(S,j)+flow(j,i)+flow(i,T)=c_{ij}+d_{ij}$。
    然后跑一遍最小割,就得到了不能被满足的那些收益,答案即为总收益-最小割。

    细节:
    1.因为建图时的规则比较多,可能会导致两点见被连了多条边,因此可以将两点之间的边合并成一条。
    2.合并的时候不能直接用一个$V imes V$的数组存($V$为原图中点数),这样会MLE,用map或者hash_map的也不好。
    3.因为除了$S$和$T$外,其它的元素之间只有相邻的四个点才可能有边,因此可以考虑只记录相邻元素的边的情况,这样内存比较小,时间也会比较快。
    4.lych有一个神奇的加边方法,就是先用数组把输入数据存起来,然后加边的时候统一计算即可,代码只有57行。

      1 #include<queue>
      2 #include<cstdio>
      3 #include<cctype>
      4 #include<vector>
      5 #include<cstring>
      6 inline int getint() {
      7     char ch;
      8     while(!isdigit(ch=getchar()));
      9     int x=ch^'0';
     10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     11     return x;
     12 }
     13 const int inf=0x7fffffff;
     14 int s,t;
     15 const int V=10002,E=80000;
     16 int ss[V]={0},left[V]={0},right[V]={0},up[V]={0},down[V]={0},tt[V]={0};
     17 struct Edge {
     18     int to,remain;
     19 };
     20 Edge e[E];
     21 int sz=0;
     22 std::vector<int> g[V];
     23 inline void add_edge(const int u,const int v,const int w) {
     24     e[sz]=(Edge){v,w};
     25     g[u].push_back(sz);
     26     sz++;
     27 }
     28 int lev[V];
     29 inline void bfs() {
     30     std::fill(&lev[1],&lev[t+1],-1);
     31     lev[s]=0;
     32     std::queue<int> q;
     33     q.push(s);
     34     while(!q.empty()) {
     35         int x=q.front();
     36         q.pop();
     37         for(unsigned i=0;i<g[x].size();i++) {
     38             Edge &y=e[g[x][i]];
     39             if(y.remain&&!~lev[y.to]) {
     40                 lev[y.to]=lev[x]+1;
     41                 q.push(y.to);
     42             }
     43         }
     44     }
     45 }
     46 unsigned cur[V];
     47 int dfs(const int x,const int flow) {
     48     if(x==t) return flow;
     49     for(unsigned &i=cur[x];i<g[x].size();i++) {
     50         Edge &y=e[g[x][i]];
     51         if(y.remain&&lev[x]<lev[y.to]) {
     52             if(int f=dfs(y.to,std::min(flow,y.remain))) {
     53                 e[g[x][i]].remain-=f;
     54                 e[g[x][i]^1].remain+=f;
     55                 return f;
     56             }
     57         }
     58     }
     59     return 0;
     60 }
     61 inline int Dinic() {
     62     int maxflow=0;
     63     for(;;) {
     64         bfs();
     65         if(!~lev[t]) break;
     66         memset(cur,0,sizeof cur);
     67         while(int flow=dfs(s,inf)) {
     68             maxflow+=flow;
     69         }
     70     }
     71     return maxflow;
     72 }
     73 int main() {
     74     int n=getint(),m=getint();
     75     s=0,t=n*m+1;
     76     int sum=0;
     77     for(int i=1;i<=n;i++) {
     78         for(int j=1;j<=m;j++) {
     79             int w=getint()<<1;
     80             sum+=w;
     81             ss[(i-1)*m+j]+=w;
     82         }
     83     }
     84     for(int i=1;i<=n;i++) {
     85         for(int j=1;j<=m;j++) {
     86             int w=getint()<<1;
     87             sum+=w;
     88             tt[(i-1)*m+j]+=w;
     89         }
     90     }
     91     for(int i=1;i<n;i++) {
     92         for(int j=1;j<=m;j++) {
     93             int w=getint();
     94             sum+=w<<1;
     95             down[(i-1)*m+j]+=w;
     96             up[i*m+j]+=w;
     97             ss[(i-1)*m+j]+=w;
     98             ss[i*m+j]+=w;
     99         }
    100     }
    101     for(int i=1;i<n;i++) {
    102         for(int j=1;j<=m;j++) {
    103             int w=getint();
    104             sum+=w<<1;
    105             down[(i-1)*m+j]+=w;
    106             up[i*m+j]+=w;
    107             tt[(i-1)*m+j]+=w;
    108             tt[i*m+j]+=w;
    109         }
    110     }
    111     for(int i=1;i<=n;i++) {
    112         for(int j=1;j<m;j++) {
    113             int w=getint();
    114             sum+=w<<1;
    115             right[(i-1)*m+j]+=w;
    116             left[(i-1)*m+j+1]+=w;
    117             ss[(i-1)*m+j]+=w;
    118             ss[(i-1)*m+j+1]+=w;
    119         }
    120     }
    121     for(int i=1;i<=n;i++) {
    122         for(int j=1;j<m;j++) {
    123             int w=getint();
    124             sum+=w<<1;
    125             right[(i-1)*m+j]+=w;
    126             left[(i-1)*m+j+1]+=w;
    127             tt[(i-1)*m+j]+=w;
    128             tt[(i-1)*m+j+1]+=w;
    129         }
    130     }
    131     for(int i=1;i<=n;i++) {
    132         for(int j=1;j<=m;j++) {
    133             add_edge(s,(i-1)*m+j,ss[(i-1)*m+j]);
    134             add_edge((i-1)*m+j,s,0);
    135         }
    136     }
    137     for(int i=1;i<n;i++) {
    138         for(int j=1;j<m;j++) {
    139             add_edge((i-1)*m+j,i*m+j,down[(i-1)*m+j]);
    140             add_edge(i*m+j,(i-1)*m+j,up[i*m+j]);
    141             add_edge((i-1)*m+j,(i-1)*m+j+1,right[(i-1)*m+j]);
    142             add_edge((i-1)*m+j+1,(i-1)*m+j,left[(i-1)*m+j+1]);
    143         }
    144     }
    145     for(int i=1;i<n;i++) {
    146         add_edge(i*m,(i+1)*m,down[i*m]);
    147         add_edge((i+1)*m,i*m,up[(i+1)*m]);
    148     }
    149     for(int j=1;j<m;j++) {
    150         add_edge((n-1)*m+j,(n-1)*m+j+1,right[(n-1)*m+j]);
    151         add_edge((n-1)*m+j+1,(n-1)*m+j,left[(n-1)*m+j+1]);
    152     }
    153     for(int i=1;i<=n;i++) {
    154         for(int j=1;j<=m;j++) {
    155             add_edge((i-1)*m+j,t,tt[(i-1)*m+j]);
    156             add_edge(t,(i-1)*m+j,0);
    157         }
    158     }
    159     printf("%d
    ",(sum-Dinic())>>1);
    160     return 0;
    161 }
  • 相关阅读:
    转自:stuff字符串拼接方法
    mssql sqlserver in 关键字在值为null的应用举例
    mssql sqlserver 将字段null(空值)值替换为指定值的三种方法分享
    mssql sqlserver 使用sql脚本输出交替不同的背景色的html信息的方法分享
    MSSQL coalesce系统函数简介
    MSSQL sql server order by 1,2 的具体含义
    JavaScript正则表达式模式匹配(1)——基本字符匹配
    正则表达式的语法和使用说明
    log4j日志的基本使用方法(1)——概述、配置文件
    写在博客园开博第一篇博文
  • 原文地址:https://www.cnblogs.com/skylee03/p/7462829.html
Copyright © 2011-2022 走看看