参考: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. 《gis空间分析及应用案例解析》培训总结

    <gis空间分析及应用案例解析>培训总结 来源:常德水情 作者:唐校准 发布日期:2014-01-02       2013年12月2630日由中国科学院计算技术研究所教育中心组织的< ...

  2. linux 中断机制浅析

    一.中断相关结构体 1.irq_desc中断描述符 struct irq_desc { #ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED struct irq_ ...

  3. 【scrapy】Item及Spider

    Items Item objects are simple containers used to collect the scraped data.They provide a dictionary- ...

  4. Visual Studio VS2010 如何修改默认的编辑语言

    1 比如我要把默认是C++的配置改成C#,在工具-导入和导出设置中,重置所有设置 2 这里改成新的语言 3 重置完成

  5. Win8系统如何关闭用户账户控制UAC

    按WIN+S,屏幕右侧出现搜索框,在搜索框中输入UAC,然后单击"更改用户账户控制设置"   然后把弹出的窗口改成"从不通知"就可以了  

  6. Angular2.x-显示heroes列表

    在此页面中,您将展开Tour of Heroes应用程序以显示heroes列表,并允许用户选择heroes并显示heroes的详细信息. 6.X 你需要一些heroes来展示. 最终你会从远程数据服务 ...

  7. 编程基础知识——Java JNI开发流程(2)

    android中使用jni调用本地C++库 android平台上的本地库文件后缀 .so.类似windows上的dll文件. 要在android上使用jni.首先须要下载android ndk. 操作 ...

  8. 深度学习笔记之关于基本思想、浅层学习、Neural Network和训练过程(三)

    不多说,直接上干货! 五.Deep Learning的基本思想 假设我们有一个系统S,它有n层(S1,…Sn),它的输入是I,输出是O,形象地表示为: I =>S1=>S2=>….. ...

  9. 解决Struts配置文件里无提示信息的问题

    (1)在struts2配置文件编写的时候.有可能无法提示所有信息,在配置文件里打个"<" 后,并没有不论什么的提示信息(使用快捷键Alt+/ 也不提示) 原因是下边的  &q ...

  10. Java基础面试:集合、内部类、线程

    package test; import java.util.Hashtable; import java.util.Map; public class test { public static St ...