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. 2017 .NET 開發者須知

    筆記-Scott Hanselman 的 2017 .NET 開發者須知 转载http://blog.darkthread.net/post-2017-01-16-dotnet-dev-should- ...

  2. Unity3d 基本设计开发 原则(提高代码可读性)

    参考:http://blog.csdn.net/qq_34134078/article/details/51780356 1.单一原则 即:明确类的定义.通俗来讲,让他们只做一件事,而不是多件事. 提 ...

  3. matlab输入输出语句(input、disp、fprintf)

    输入语句 输入数值 ?x=input('please input a number:') please input a number:22 x = 22 输入字符串 ?x=input('please ...

  4. Linux三剑客之awk最佳实践

    笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 知识点: 记录与字段 模式匹配:模式与动作 基本的awk执行过程 awk常用内置变量(预定义变量) awk数组 a ...

  5. 【转】GPS误差来源

    一.与GPS卫星有关的误差 1.卫星时钟误差 即使卫星是非常的精密复杂,它可以计算出一些极微小的讯息信息,如原子钟(Cesium) 即是如此一个精准的装置,但是精准并不代表完美,因此仍会有一些微小的误 ...

  6. oracle游标的知识点

    游标: 就是一个结果集(ResultSet) 游标语法: CURSOR 光标名 [(参数名 数据类型[,参数名 数据类型])] IS SELECT 语句; eg. cursor c1 is selec ...

  7. mybatis不可忽略的细节

    自我总结,欢迎拍砖! 目的:在需要返回int,long等基础类型数据的情况下,尽量在mybatis的Mapper中用基础类型的包装类. 原因:当查询的字段为空值时,mybatis会返回null,用基础 ...

  8. android adb shell and monkey 学习记录

    Monkey环境: android SDK and JDK SDK目录下的platform-tools和tools目录要配置环境变量 查看版本: ADB 的安装这里就不多说了,输入以下命令有如下提示就 ...

  9. BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]

    4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...

  10. document.activeElement 过滤选择文件弹窗导致的页面失焦

    在线考试页面,常常需要检测用户是否作弊. 一般是监听页面是否失焦的方式,而失焦的方式有很多种,比如QQ弹窗,切换页面,切换程序,input文件上传选择文件等 选择文件是正常情况,这种情况下需要过滤 本 ...