网络流
好东西,可以学
2022.3.25更新
确实是好东西,下次再更
2022.3.25晚
总有人抱怨我写的太认真/lh,我不会markdown我也很无奈啊/yun。
网络流24题网上比我写的好的很多,我就不献丑了,接下来我们就讲讲最小割吧
例题1:【模板】最小割
好的你已经掌握了最小割的全部内容,接下来就拿几题练练手吧!
练习一:[THUPC2022 初赛] 分组作业
相信聪明的你已经做出来了,那么我说说我的做法。
考虑最小割的本质。
将每个点赋0,1值,我们称之为\(w_i\),我们要求的就是\(w_S=1,w_T=0\)情况下,$$\min({a_{i,j} \times\max(w_i-w_j,0)})$$
什么是最小割呢?所谓最小割,就是最小的隔断,至于为什么是最小的隔断,小编也很惊讶。
以上就是有关最小割的所有内容,欢迎评论区讨论吧!
~~~~~~~~~~~~~~~~~~~~开玩笑的~~~~~~~~~~~~~~~~~
对于这个模型,我们举个栗子来理解一下
有 \(n\) 个物品和两个集合 \(A,B\) ,如果一个物品放入 \(A\) 集合会花费 \(a_i\),放入 \(B\) 集合会花费 \(b_i\) ;还有若干个形如 \(u_i,v_i,x_i\) 限制条件,表示如果\(u_i\) 和 \(v_i\) 同时不在一个集合会花费\(x_i\)。每个物品必须且只能属于一个集合,求最小的代价。
这是一个经典的 二者选其一 的最小割题目,解法相信大家都知道。我们设置源点 \(S\)和汇点\(T\) ,第 \(i\) 个点由 \(S\) 连一条容量为 \(a_i\) 的边、向 \(T\) 连一条容量为\(b_i\) 的边。对于限制条件 \(u_i,v_i,x_i\),我们在\(u_i,v_i\) 之间连容量为 \(x_i\) 的双向边。
如果用刚刚那个公式理解的话。先不考虑物品间的影响,\(w_i=0\)可以认为物品在A中,这时候答案加了\(a_i\),正好对应\(w_S-w_i=1\)答案加了\(a_i\);\(w_i=1\)时同理。
再来考虑物品间的影响,发现如果两个物品不在同一个集合的话,\(w_i\)是不同的,又因为连的是双向边,因此答案会加\(x_i\)
个人感觉相比一条条看哪条边被割,这种理解方式更简单,不容易出错
只要定好了\(w_i\)的意义,根据题面的要求连边,一些题目还是很简单的,比如这题/cy
回到这道题,通过上述例子,相信大家已经对这个模型有所了解,这道题可以说是这个模型的入门题
我们定两类点:团队点和个人点。\(w_i=1\)代表合作。
然后连边就好了,是不是很简单/yiw
唯一有点意思的就是如何限制团队点和个人点的关系,我们发现团队点的\(w\)值一定小于个人点,因此我们可以将团队点向个人点连流量为无限大的边,这道题就做完了
我们发现一个小技巧:我们如果想让\(w_i<=w_j\),只要\(i\)向\(j\)连一条流量无限大的边即可
code:
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
inline int read () {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
const int N=16005;
int n,m,head[N],k=1,dep[N],S,T,o=(1<<30);
struct Node{
int nex,to,w;
}e[N*50];
void add(int u,int v,int w){
e[++k].to=v;
e[k].nex=head[u];
e[k].w=w;
head[u]=k;
}
void ad(int u,int v,int w){
add(u,v,w);add(v,u,0);
}
queue<int> q;
bool bfs(){
memset(dep,0,sizeof(dep));
q.push(S);
dep[S]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for (int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(e[i].w&&!dep[v]){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
if(dep[T]) return 1;
return 0;
}
int dfs(int u,int in){
if(u==T) return in;
int out=0;
for (int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(e[i].w&&dep[v]==dep[u]+1){
int res=dfs(v,min(in,e[i].w));
in-=res;
out+=res;
e[i].w-=res;
e[i^1].w+=res;
}
}
if(out==0) dep[u]=0;
return out;
}
int team(int i){
return (i+1)/2+2*n;
}
signed main (){
// freopen("in.in", "r", stdin);
// freopen("out.out", "w", stdout);
n=read();m=read();
S=3*n+1;T=S+1;
for (int i=1;i<=2*n;i++){
int c=read(),d=read(),e=read();
if(i&1) ad(i,i+1,e);
else ad(i,i-1,e);
ad(S,i,d);ad(i,T,c);
ad(team(i),i,o);
}
for (int i=1;i<=m;i++){
int A=read(),B=read(),a=read(),b=read();
ad(B,team(A),a);
ad(team(B),A,b);
}
int ans=0;
while(bfs()) ans+=dfs(S,o);
printf("%lld\n",ans);
return 0;
}
咕着,遇到好题再更

浙公网安备 33010602011771号