参考:https://www.cnblogs.com/chenyushuo/p/5144957.html 不得不说这个建图方法真是非常妙啊

假设S点选理,T点选文,a[i][j]为(i,j)选文收益,b[i][j]为(i,j)选理收益,c[i][j]为同时选文收益,d[i][j]为同时选文收益。

那么对于每个点x=(i+1)*m+j,我们连接

\[c[s,x]=b[i][j]
\]

\[c[x,t]=a[i][j]
\]

对于有利益相关的x,y两点,连接

\[c[s,x]=d[i][j]/2
\]

\[c[s,y]=d[i][j]/2
\]

\[c[x,t]=c[i][j]/2
\]

\[c[y,t]=c[i][j]/2
\]

\[c[x,y]=c[i][j]/2+d[i][j]/2
\]

\[c[y,x]=c[i][j]/2+d[i][j]/2
\]

建完的图:



然后考虑最小割,下面枚举几种情况:

都选文,即割掉了x选理,y选理和(x,y)都选理:



都选理,即割掉了x选文,y选文和(x,y)都选文:



x选文y选理,即割掉了x选理,y选文,(x,y)都选理/+(x,y)都选理/2+(x,y)都选文/2+(x,y)都选文/2,即,割掉x选理,y选文,(x,y)都选理,(x,y)都选文:



y选文x选理,即割掉了x选文,y选理,(x,y)都选理/+(x,y)都选理/2+(x,y)都选文/2+(x,y)都选文/2,即,割掉x选文,y选理,(x,y)都选理,(x,y)都选文:

对于除以2的操作,为避免下取整的误差,我们选择把所有流量都*2,最后再/2。

$ ans=sum(全部收益)- 最小割 $

p.s.用邻接表建图的时候先把每个点选单科的边连上,再练同时选的收益,否则会重

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=105,E=1000005,inf=1e9,P=500005;
int n,m,a[N][N],b[N][N],c[N][N],d[N][N],s,t,sum,cnt=1,h[P],le[N*N];
struct qwe
{
int ne,to,va;
}e[E];
int read()
{
int r=0;
char p=getchar();
while(p<'0'||p>'9')
p=getchar();
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r;
}
void add(int u,int v,int w)
{
cnt++;
e[cnt].ne=h[u];
e[cnt].to=v;
e[cnt].va=w;
h[u]=cnt;
}
bool bfs()
{
queue<int>q;
memset(le,0,sizeof(le));
le[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();//cout<<u<<"AAAAAAAAAAAA"<<endl;
q.pop();
for(int i=h[u];i;i=e[i].ne)
if(e[i].va&&!le[e[i].to])
{
le[e[i].to]=le[u]+1;
q.push(e[i].to);
}
}
// for(int i=0;i<=5;i++)
// cout<<le[i]<<" ";
return le[t];
}
int dfs(int u,int f)
{//cout<<u<<" "<<f<<endl;
if(u==t)
{
//cout<<"!!";
return f;
}
int used=0;
for(int i=h[u];i;i=e[i].ne)
{
//cout<<u<<" "<<e[i].to<<" "<<e[i].va<<endl;;
if(e[i].va>0&&le[e[i].to]==le[u]+1)
{//cout<<"OK"<<endl;
int w=dfs(e[i].to,min(f-used,e[i].va));
e[i].va-=w;
e[i^1].va+=w;
used+=w;
if(used==f)
return f;
}
}
if(!used)
le[u]=-1;
return used;
}
int dinic()
{
int ans=0;
while(bfs())
ans+=dfs(s,inf);//,cout<<ans<<endl;
return ans;
}
int main()
{
n=read(),m=read();
s=0,t=n*m+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read(),sum+=a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=read(),sum+=b[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x=(i-1)*m+j;
add(s,x,b[i][j]<<1);
add(x,s,0);
add(x,t,a[i][j]<<1);
add(t,x,0);
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
c[i][j]=read(),sum+=c[i][j];
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
d[i][j]=read(),sum+=d[i][j];
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
{
int x=(i-1)*m+j,y=i*m+j;
add(s,x,d[i][j]);
add(x,s,0);
add(s,y,d[i][j]);
add(y,s,0);
add(x,y,c[i][j]+d[i][j]);
add(y,x,c[i][j]+d[i][j]);
add(x,t,c[i][j]);
add(t,x,0);
add(y,t,c[i][j]);
add(t,y,0);
}
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
c[i][j]=read(),sum+=c[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
d[i][j]=read(),sum+=d[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
{
int x=(i-1)*m+j,y=(i-1)*m+j+1;
add(s,x,d[i][j]);
add(x,s,0);
add(s,y,d[i][j]);
add(y,s,0);
add(x,y,c[i][j]+d[i][j]);
add(y,x,c[i][j]+d[i][j]);
add(x,t,c[i][j]);
add(t,x,0);
add(y,t,c[i][j]);
add(t,y,0);
}
printf("%d\n",sum-(dinic()>>1));
return 0;
}

bzoj 2127 happiness【最小割+dinic】的更多相关文章

  1. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  2. [置顶] [BZOJ]2127: happiness 最小割

    happiness: Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己 ...

  3. BZOJ 2127: happiness(最小割解决集合划分)

    Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 2350  Solved: 1138[Submit][Status][Discuss] Descript ...

  4. [BZOJ 2127] happiness 【最小割】

    题目链接:BZOJ - 2127 题目分析 首先,每个人要么学文科,要么学理科,所以可以想到是一个最小割模型. 我们就确定一个人如果和 S 相连就是学文,如果和 T 相连就是学理. 那么我们再来确定建 ...

  5. BZOJ 2127 / Luogu P1646 [国家集训队]happiness (最小割)

    题面 BZOJ传送门 Luogu传送门 分析 这道题又出现了二元关系,于是我们只需要解方程确定怎么连边就行了 假设跟SSS分在一块是选文科,跟TTT分在一块是选理科,先加上所有的收益,再来考虑如何让需 ...

  6. [国家集训队]happiness 最小割 BZOJ 2127

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

  7. bzoj 3144 [Hnoi2013]切糕【最小割+dinic】

    都说了是'切'糕所以是最小割咯 建图: 每个点向下一层连容量为这个点的val的边,S向第一层连容量为inf的边,最后一层向T连容量为自身val的边,即割断这条边相当于\( f(i,j) \)选择了当前 ...

  8. [bzoj2127]happiness——最小割

    这个题太恶心了...并不想继续做了... 本代码在bzoj上TLE! 大致说一下思路: 建立ST,首先由S连边(S,u,a)a代表学文的分数,连向T(u,T,b)b表示学理的分数,这样构造出了两个人独 ...

  9. spoj 839 OPTM - Optimal Marks&&bzoj 2400【最小割】

    因为是异或运算,所以考虑对每一位操作.对于所有已知mark的点,mark的当前位为1则连接(s,i,inf),否则连(i,t,inf),然后其他的边按照原图连(u,v,1),(v,u,1),跑最大流求 ...

随机推荐

  1. ACM-ICPC 2018 焦作赛区网络预赛 H、L

    https://nanti.jisuanke.com/t/31721 题意 n个位置 有几个限制相邻的三个怎么怎么样,直接从3开始 矩阵快速幂进行递推就可以了 #include <bits/st ...

  2. 教你如何查看CAD文件是哪个版本的来自http://blog.sina.com.cn/s/blog_4c9fa4dd0101il1v.html

    教你如何查看CAD文件是哪个版本的 http://blog.sina.com.cn/s/blog_4c9fa4dd0101il1v.html (2013-03-10 22:24:52) 转载▼ 标签: ...

  3. Guice 学习(八)AOP (面向切面的编程)

    Guice的AOP还是非常弱的.眼下只支持方法级别上的,另外灵活性也不是非常高. 看例如以下演示样例: Guice支持AOP的条件是: 类必须是public或者package (default) 类不 ...

  4. Binder系列8—如何使用Binder(转)

    一.Native层Binder 源码结构: ClientDemo.cpp: 客户端程序 ServerDemo.cpp:服务端程序 IMyService.h:自定义的MyService服务的头文件 IM ...

  5. Linux程序设计(搭建开发环境--curses)

    看官们.咱们今天要说的内容.是前面内容的一点小补充,详细的内容是:安装curses开发包.以搭建 开发环境.闲话休说,言归正转. 我们在前面说过搭建开发环境的内容,主要说了开发环境中的GCC和VIM, ...

  6. JavaSE----API之集合(Collection、List及其子类、Set及其子类、JDK1.5新特性)

    5.集合类 集合类的由来: 对象用于封装特有数据,对象多了须要存储:假设对象的个数不确定.就使用集合容器进行存储. 集合容器由于内部的数据结构不同,有多种详细容器.不断的向上抽取,就形成了集合框架. ...

  7. PHP出现Warning: A non-numeric value encountered问题的原因及解决方法

    本文介绍php出现Warning: A non-numeric value encountered问题,用实例分析出现这种错误的原因,并提供避免及解决问题的方法. <?php error_rep ...

  8. 2016/04/29 ①cms分类 ② dede仿站制作 步骤 十个步骤 循环生成菜单 带子菜单的菜单 标签 栏目 栏目内容列表 内容图片列表

    cms 系统还有: phpcms     企业站 Xiaocms  织梦  企业站 wordpress (博客) Ecshop 商城 Ecmall 多用户 Discms 记账 方维 订餐 团购 CMS ...

  9. 汉诺塔算法c++源代码(递归与非递归)[转]

     算法介绍: 其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n - 1(有兴趣的可以自己证明试试看).后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了.首先把三根柱 ...

  10. mysql04--存储过程

    过程:若干语句,调用时执行封装的体.没有返回值的函数. 函数:是一个有返回值的过程 存储过程:把若干条sql封装起来,起个名字(过程),并存储在数据库中. 也有不存储的过程,匿名过程,用完就扔(mys ...