link

最小割

双倍经验

这道题运用了最小割最常用的一种用法:集合划分

因为源汇最小割即就是将源汇划分到不同的集合,那么最简单的应用就是最小代价划分集合了。

本题中,题意是将 \(n\cdot m\) 个学生划分文理科,每人只能选一科且选不同的科有不同的收益,求最大收益,符合集合划分的条件,就理所当然地想到了最小割。

至于求最大收益,不妨就先将所有收益加起来,再减去最小代价(即最小割),便是最大收益了。

但是本题的难点在于,如果相邻同学选一样的(以下称为一个组合),还会有额外收益。

于是我们需要加一点限制,使得我们在最后求最小割的时候,对于每一个组合:要么满足组合内的所有成员,都在同一个子集(包含源点的子集 \(S\) 或包含汇点的子集 \(T\)),且那条代表额外收益的边不会被割掉;要么不满足组合内是所有成员,都在同一个子集,且那条代表额外收益的边被割掉了

于是大致见图思路出来了:

  • 对于每一个点(每一位同学)\(i\):

    连 \(s\rightarrow i\) 容量为 \(art_i\);

    连 \(i\rightarrow t\) 容量为 \(science_i\)。

  • 对于每一个组合 \(i\),新建两个点 \(x_i,y_i\):

    连 \(s\rightarrow x_i\) 容量为 \(same\_art_i\);

    连 \(y_i\rightarrow t\) 容量为 \(same\_science_i\)。

    对于该组合内的每个点(即该点+上下左右四个点)\(j\in i\):

    连 \(x_i\rightarrow j\) 容量为 \(+\infty\);

    连 \(j\rightarrow y_i\) 容量为 \(+\infty\)。

这里解释一下这么连的原因:

如果要 \(s\rightarrow x_i\) 这条边(即要这个组合所有同学都选文科的收益),那么就不割这条边。但是,又因为 \(x_i\) 向这个组合内每个点都连了一条 \(+\infty\) 的边,所以这些边便不会被割掉。那么为了防止 \(s\) 与 \(t\) 联通,自然就会割掉这个组合内每个点与 \(t\) 连的边(即都不选理科)。反之都选理科亦然。

如果放弃这个组合(即这个组合内每个成员选的科不都一样),那么就会割掉 \(s\rightarrow x_i\) 和 \(y_i\rightarrow t\) 这两条边,那么就相当于这个组合内的每个点都互相独立了,可以任意选科。

:不能将 \(x_i\) 与 \(y_i\) 合并成一个点来连边,这样会使上述放弃组合的情况无法达到(即无法破坏组合独立选择)。

Code

#include<bits/stdc++.h>
//#define int long long
#define pair pair<int,int>
using namespace std;
inline void end()
{
puts("");
system("pause");
}
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const int N=3e4+4,M=5e5+5;
int n,m,nm,s,t,ans,Maxflow;
int first[N],nex[M],to[M],w[M],num=1;
inline void add(int u,int v,int val)
{
nex[++num]=first[u];
first[u]=num;
to[num]=v;
w[num]=val;
}
inline void Add(int u,int v,int val)
{
add(u,v,val);
add(v,u,0);
}
namespace ISAP
{
int dep[N],gap[N],cur[N];
void bfs()
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
queue<int> q;
q.push(t);
dep[t]=0;gap[0]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=first[u];i;i=nex[i])
{
int v=to[i];
if(dep[v]!=-1) continue;
dep[v]=dep[u]+1;
gap[dep[v]]++;
q.push(v);
}
}
}
inline int dfs(int u,int in)
{
if(u==t) return in;
int out=0;
for(int i=cur[u];i;i=nex[i])
{
cur[u]=i;
int v=to[i];
if(!w[i]||dep[v]!=dep[u]-1) continue;
int res=dfs(v,min(w[i],in-out));
w[i]-=res;
w[i^1]+=res;
out+=res;
if(in==out) return out;
}
gap[dep[u]]--;
if(!gap[dep[u]]) dep[s]=3*nm+3;
dep[u]++;
gap[dep[u]]++;
return out;
}
void work()
{
bfs();
while(dep[s]<3*nm+2)
{
memcpy(cur,first,sizeof(first));
Maxflow+=dfs(s,1e9);
}
}
}
inline int id(int i,int j){return (i-1)*m+j;}
int dx[5]={-1,0,1,0,0},dy[5]={0,-1,0,1,0};
int main()
{
//1|nm|nm|nm|1
//源点|每个组合"选文"|每个座位|每个组合"选理"|汇点
n=read(),m=read(),nm=n*m;
s=0,t=3*nm+1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int val=read();ans+=val;
Add(s,id(i,j)+nm,val);//s -> i
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int val=read();ans+=val;
Add(id(i,j)+nm,t,val);//i -> t
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int val=read();ans+=val;
Add(s,id(i,j),val);//s -> x_i
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int val=read();ans+=val;
Add(id(i,j)+2*nm,t,val);//y_i -> t
for(int k=0;k<5;++k)
{
int x=i+dx[k],y=j+dy[k];
if(x<1||y<1||x>n||y>m) continue;
Add(id(i,j),id(x,y)+nm,1e9);//x_i -> j
Add(id(x,y)+nm,id(i,j)+2*nm,1e9);//j -> y_i
}
}
}
ISAP::work();
printf("%d",ans-Maxflow);
end();
return 0;
}

Luogu P4313 文理分科的更多相关文章

  1. BZOJ 3894 Luogu P4313 文理分科 (最小割)

    题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3894 (luogu) https://www.luogu.org/pro ...

  2. BZOJ 3894 / Luogu P4313 文理分科 (拆点最小割)

    题面 中文题面- BZOJ 传送门 Luogu 传送门 分析 这道题类似于BZOJ 3774 最优选择,然后这里有一篇博客写的很好- Today_Blue_Rainbow's Blog 应该看懂了吧- ...

  3. P4313 文理分科 最小割

    $ \color{#0066ff}{ 题目描述 }$ 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行描述,每个格 ...

  4. P4313 文理分科

    思路 遇到这种利益冲突的最终利益最大化问题 考虑转化为最小割,使得损失的价值最小 相当于文科是S,理科是T,选出最小割就是确定损失代价最小的方案 然后就把S向每个点连一条cap=art[i][j]的边 ...

  5. BZOJ 3894: 文理分科 [最小割]

    3894: 文理分科 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 674  Solved: 392[Submit][Status][Discuss] ...

  6. Bzoj3894 文理分科

    Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 667  Solved: 389 Description  文理分科是一件很纠结的事情!(虽然看到这个题 ...

  7. bzoj 3894: 文理分科

    Description  文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过)  小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行 描述,每个格子代表一个同学的座位. ...

  8. BZOJ_3894_文理分科&&BZOJ_2127_happiness_最小割

    BZOJ_3894_文理分科_最小割 Description  文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过)  小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进 ...

  9. BZOJ3894文理分科——最小割

    题目描述  文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过)  小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行 描述,每个格子代表一个同学的座位.每位同学必须从 ...

随机推荐

  1. GO语言面向对象04---接口的继承

    package main import "fmt" type Animal interface { Eat(food string) (shit string) GoDie() } ...

  2. 单线程service服务

    1.@Service修饰类名,同时类继承Thread类 @Service public class MasterSchedulerService extends Thread { /** * logg ...

  3. CVPR2020最新论文扫描盘点(上)

    CVPR2020最新论文扫描盘点(上) 最近计算机视觉三大顶会之一CVPR2020接收结果已经公布,一共有1470篇论文被接收,接收率为22%,相比去年降低3个百分点,竞争越来越激烈.这里整理来自Tw ...

  4. ARM CPU自动调度神经网络

    ARM CPU自动调度神经网络 对特定设备和工作负载进行自动调度,对于获得最佳性能至关重要.通过RPC使用自动调度器为ARM CPU调度整个神经网络. 为了自动调度神经网络,将网络划分为小的子图,进行 ...

  5. 在cuDNN中简化Tensor Ops

    在cuDNN中简化Tensor Ops 在Tesla V100 GPU中引入神经网络模型以来,神经网络模型已迅速利用NVIDIA Tensor Cores进行深度学习.例如,基于Tensor Core ...

  6. the rust book 的简单入门笔记

    rust learning day 1 (2021/05/27) 学了常量,变量,数据类型,控制流,所有权 char 的宽度是4字节,一个 unicode 的宽度 控制流条件都不要括号 rust 中的 ...

  7. 十一、diff和patch打补丁

    diff制作补丁文件的原理:告诉我们怎么修改第一个文件后能得到第二个文件. diff命令常用选项: -u 输出统一内容的头部信息(打补丁使用),计算机知道是哪个文件需要修改    -r 递归对比目录中 ...

  8. 【Android编程实战】源码级免杀_Dex动态加载技术_Metasploit安卓载荷傀儡机代码复现

    /文章作者:MG193.7 CNBLOG博客ID:ALDYS4 QQ:3496925334/ 在读者阅读本文章前,建议先阅读笔者之前写的一篇对安卓载荷的分析文章 [逆向&编程实战]Metasp ...

  9. 基于Android平台的图书管理系统的制作(4)

    讲解完学生.职员.书籍这些基础层之后,我们可以来了解一些应用层的活动. 新书上架.借阅排行.黑名单.图书馆介绍.图书馆新闻. 新书上架是查询数据库里的Book表,将最近注册的五本书的基本信息(若图书馆 ...

  10. Pandas高级教程之:处理缺失数据

    目录 简介 NaN的例子 整数类型的缺失值 Datetimes 类型的缺失值 None 和 np.nan 的转换 缺失值的计算 使用fillna填充NaN数据 使用dropna删除包含NA的数据 插值 ...