Time Limit: 1000 ms   Memory Limit: 256 MB

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的非负整数
 

Solution

  这种相邻格子的问题,一般都是考虑两个相邻的格子的最小割模型,然后把所有模型叠加起来。

  现在考虑相邻的两人$x$和$y$。$x$选文或理的收益是$x_0,x_1$;$y$选文或理的收益是$y_0,y_1$;都选文的收益是$s_0$,都选理的收益是$s_1$。

  那么从总收益$sum=x_0+x_1+y_0+y_1+s_0+s_1$中减去最小割就是最优解。

  考虑一下逻辑关系:

    (1)如果$x$和$y$都选文,那么需要割去$x_1,y_1,s_1$

    (2)如果$x$和$y$都选理,那么需要割去$x_0,y_0,s_0$

    (3)如果$x$文$y$理,那么需要割去$x_1,y_0,s_0,s_1$

    (4)如果$x$理$y$文,那么需要割去$x_0,y_1,s_0,s_1$

  发现一个人选一科,必定割掉另外一科的喜悦值。那么由源点$S$向$x$连$x_0$的边,向$y$连$y_0$的边;$x$向汇点$T$连$x_1$的边,向$y$连$y_1$的边。

  

   现在,(1)和(2)还差$s_0$和$s_1$未刻画。因为割掉两条边以后貌似图就彻底分开了,不好再加入新的边来体现,我们考虑将$s_0$附加在$x_0$与$y_0$上,将$s_1$附加在$x_1$与$y_1$上,即各分一半:

   

  (1)和(2)刻画完毕。但是(3)和(4)在其中不适用了。

  如果$x$选文,$y$选理,那么割去的边是右上和左下两条边,其权值之和是$x_1+\frac{1}{2}s_1+y_0+\frac{1}{2}s_0$,但是我们期望的是$x_1+y_0+s_0+s_1$,不对啊。

  怎么办?期望值和当前值一作差,得$\frac{1}{2}s_0+\frac{1}{2}s_1=\frac{1}{2}(s_0+s_1)$。想办法把它实例化!当割去的是右上和左下两条边时,已经形成最小割,那么强行把这条边塞进去!由$y$向$x$连一条权值为$\frac{1}{2}(s_0+s_1)$的调整边即可。

  $x$理$y$文同理。

  

  中间的两条调整边,仅在二者文理不同的时候起作用。现在这个模型,已经可以刻画(1)~(4)所有的情况了。

  对全图进行建模,跑出最小割,用总收益和减去最小割即可。

Important:

  我们不能对于每两个格子都像如上模型一样连接$(S,x),(S,y),(x,T),(y,T)$,将总收益和看做每两个格子的$sum$之和,然后将模型并起来跑。

  为什么?因为这样我们会发现某一些$x_0$、$x_1$和$y_0$、$y_1$被多算了几次,这是极不好的,模型之间出现了交集。

  事实上对于一个点$x$,我们将所有$S$->$x$的边都合并起来:即权值应该为:$x_0$或$y_0$加上$\frac{1}{2} \sum s_0$。$x$到$T$的边同理。

  而中间的调整边照常即可。

  这样当$sum$为所有格子的收益和的时候,用$sum$减去最小割的答案是对的。

Tips:

  可以将边权乘上2,跑出最小割后除以2,即可忽略小数。


#include <cstdio>
#include <queue>
using namespace std;
const int N=,INF=;
int n,m,a[][],b[][],ax[][],ay[][],bx[][],by[][];
int sum;
int S,T,dis[N],cur[N],h[N],tot;
queue<int> q;
struct Edge{int v,next,f;}g[N*];
inline int id(int x,int y){return (x-)*m+y;}
inline int min(int x,int y){return x<y?x:y;}
inline void addEdge(int u,int v,int f){
g[++tot].v=v; g[tot].f=f; g[tot].next=h[u]; h[u]=tot;
g[++tot].v=u; g[tot].f=; g[tot].next=h[v]; h[v]=tot;
}
bool bfs(){
while(!q.empty()) q.pop();
q.push(S);
for(int i=;i<=T;i++) dis[i]=-;
dis[S]=;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=h[u],v;i;i=g[i].next)
if(g[i].f&&dis[v=g[i].v]==-){
dis[v]=dis[u]+;
if(v==T) return true;
q.push(v);
}
}
return dis[T]!=-;
}
int dfs(int u,int delta){
if(u==T) return delta;
int ret=,get;
for(int i=cur[u],v;i&&delta;i=g[i].next)
if(g[i].f&&dis[v=g[i].v]==dis[u]+){
get=dfs(v,min(delta,g[i].f));
g[i].f-=get;
g[i^].f+=get;
if(g[i].f) cur[u]=i;
delta-=get;
ret+=get;
}
if(!ret) dis[u]=-;
return ret;
}
int dinic(){
int ret=;
while(bfs()){
for(int i=;i<=T;i++) cur[i]=h[i];
ret+=dfs(S,INF);
}
return ret;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) for(int j=;j<=m;j++) scanf("%d",&a[i][j]),sum+=a[i][j];
for(int i=;i<=n;i++) for(int j=;j<=m;j++) scanf("%d",&b[i][j]),sum+=b[i][j];
for(int i=;i<n;i++) for(int j=;j<=m;j++) scanf("%d",&ax[i][j]),sum+=ax[i][j];
for(int i=;i<n;i++) for(int j=;j<=m;j++) scanf("%d",&bx[i][j]),sum+=bx[i][j];
for(int i=;i<=n;i++) for(int j=;j<m;j++) scanf("%d",&ay[i][j]),sum+=ay[i][j];
for(int i=;i<=n;i++) for(int j=;j<m;j++) scanf("%d",&by[i][j]),sum+=by[i][j];
S=n*m+; T=n*m+; tot=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
int u=id(i,j);
addEdge(S,u,a[i][j]*+ax[i-][j]+ax[i][j]+ay[i][j-]+ay[i][j]);
addEdge(u,T,b[i][j]*+bx[i-][j]+bx[i][j]+by[i][j-]+by[i][j]);
if(i<n){
addEdge(u,id(i+,j),ax[i][j]+bx[i][j]);
addEdge(id(i+,j),u,ax[i][j]+bx[i][j]);
}
if(j<m){
addEdge(u,id(i,j+),ay[i][j]+by[i][j]);
addEdge(id(i,j+),u,ay[i][j]+by[i][j]);
}
}
int get=dinic();
get/=;
printf("%d\n",sum-get);
return ;
}

奇妙代码

【BZOJ2127】happiness的更多相关文章

  1. 【BZOJ2127】happiness(最小割)

    [BZOJ2127]happiness(最小割) 题面 Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了, ...

  2. 【bzoj2127】happiness 最大流

    happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 2579  Solved: 1245[Submit][Status][Discuss ...

  3. 【BZOJ2127】happiness 网络流

    题目描述 有\(n\times m\)个人,排成一个\(n\times m\)的矩阵.每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一 ...

  4. 【BZOJ2127】happiness 最小割

    题目大意:有一个$n\times m$的矩阵,矩阵的每个位置上有一个同学,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦 ...

  5. 【BZOJ2127】happiness(网络流)

    点此看题面 大致题意: 每个人只能在文科与理科中选择一种.选择每种科目会带来不同的喜悦值,如果相邻的两位同学选择了同一种科目则会带来额外的喜悦值.求喜悦值总和的最大值. 网络流 这道题做法显然是网络流 ...

  6. 【bzoj2127】happiness 网络流最小割

    题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文 ...

  7. 【BZOJ】【2127】happiness

    网络流/最小割 Orz Hzwer. 这题他题解说的比较简略……我手画了个图才明白过来…… 嗯对于每个人选文or理的单独收益大家应该很好理解……连S->i 权值为选文的喜悦值,i->T权值 ...

  8. 【POJ2482】【线段树】Stars in Your Window

    Description Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw ...

  9. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

随机推荐

  1. 《struts2》:指定多个配置文件和默认Action

    转载:http://m.blog.csdn.net/article/details?id=51212968

  2. @interface注解类、 @Target:注解的作用目标 @Retention

    public @interface xxx 定义注解 @interface 不是interface,是注解类 是jdk1.5之后加入的,java没有给它新的关键字,所以就用@interface 这么个 ...

  3. dotween tips

    涉及kill及复用的行为比较奇怪. 使用shortcut方式调用dotween时,每次调用都是增加一个新的tweener,如果该tweener控制的属性与上次调用相同时,会出现奇怪的行为,应该是多个t ...

  4. 反向代理和HTTP重定向

    1.什么是正向代理(前向代理)? 在NAT技术(Network Address Translation)出现之前,所有主机无法直接与外网相连,要想上网,需要连接到一台能够访问外网的Web服务器,再通过 ...

  5. java编码GBK的不可映射字符

    编译java文件时,提示编码GBK的不可映射字符. 主要原因:windows 默认编码方式为GBK,用javac编译时,中文按照GBK解析,但是文件内容编码格式不是GBK. 解决:若编译单个文件指定编 ...

  6. poj2479 最大子段和

    题意:给定一个数列.求出数列中不相交的两个子段和,要求和最大 解题思路:对每一个i来说,求出[0-i-1]的最大子段和以及[i-n-1]的最大子段和,再加起来,求出最大的一个.[0-i-1]的最大子段 ...

  7. Chocolatey 和 Redis windows安装记录

    前言 最近研究redis,发现Redis没有官方的windows版本,但MsOpenTech有一直维护对应的Redis版本,其下载地址如下: https://github.com/MSOpenTech ...

  8. wpf阻止键盘快捷键alt+space,alt+F4

    /// <summary>        /// 阻止 alt+f4和alt+space 按键        /// </summary>        /// <par ...

  9. Codeforces Round #410 (Div. 2)

    Codeforces Round #410 (Div. 2) A B略..A没判本来就是回文WA了一次gg C.Mike and gcd problem 题意:一个序列每次可以把\(a_i, a_{i ...

  10. Nodejs的运行原理-模块篇

    前言 使用Nodejs,就不可避免地引用第三方模块,它们有些是Nodejs自带的(例:http,net...),有些是发布在npm上的(例:mssql,elasticsearch...) 本篇章聚焦3 ...