首页 > 其他分享 >最大流学习笔记(待补充)

最大流学习笔记(待补充)

时间:2024-08-08 21:54:18浏览次数:11  
标签:tmp return 补充 ll cap 笔记 学习 int edge

刚学了最大流的 EK 算法和 Dinic 算法,在此做一点总结。

由于这次专题学习是偏向图论建模的,因此目前暂且不涉及算法本身。

Dinic 板子:

namespace Net{
	int S,T;
	int head[510],work[510],etot = 1;
	struct node{ int nxt,v,cap; }edge[160010];
	inline void add(int x,int y,int w){
		edge[++etot] = {head[x],y,w};
		head[x] = etot;
	}
	inline void addedge(int u,int v,int w){ add(u,v,w),add(v,u,0); }
	int dis[510];
	bool vis[510];
	bool bfs(){
		queue<int> q;
		for(int i = S;i<=T;++i)dis[i] = -1;
		dis[S] = 0;
		q.push(S);
		while(!q.empty()){
			int x = q.front(); q.pop();
			for(int i = head[x];i;i = edge[i].nxt){
				int v = edge[i].v;
				if(edge[i].cap > 0 && dis[v] == -1){
					dis[v] = dis[x] + 1;
					q.push(v);
				}
			}
		}
		return (dis[T] >= 0);
	}	
	int dfs(int u,int flow){
		if(u == T)return flow;
		for(int &i = work[u];i;i = edge[i].nxt){
			int v = edge[i].v;
			if(edge[i].cap > 0 && dis[v] == dis[u] + 1){
				int tmp = dfs(v,min(flow,edge[i].cap));
				if(tmp > 0){
					edge[i].cap -= tmp;
					edge[i^1].cap += tmp;
					return tmp;
				}
			}
		}
		return 0;
	}
	int Dinic(){
		int ans = 0;
		while(bfs()){
			for(int i = S;i<=T;++i)work[i] = head[i];
			while(1){
				int flow = dfs(S,inf);
				if(flow == 0)break;
				ans += flow;
			}
		}
		return ans;
	}
}

Dinic 邻接矩阵(没有当前弧优化)

namespace Net{
	int S,T;
	ll cap[N][N];
	
	inline void addedge(int x,int y,ll w){
		cap[x][y] = w;
		cap[y][x] = 0;
	}
	
	int dist[N];
	bool vis[N];	
	ll dfs(int u,ll flow){
		if(u == T)return flow;
		for(int i = S;i<=T;++i)if(cap[u][i] != -1){
			if(cap[u][i] > 0 && dist[i] == dist[u] + 1){
				int tmp = dfs(i,min(cap[u][i],flow));
				if(tmp > 0){
					cap[u][i] -= tmp;
					cap[i][u] += tmp;
					return tmp;
				}
			}
		}
		return 0;
	}
	

	bool bfs(){
		queue<int> q;
		for(int i = S;i<=T;++i)dist[i] = -1;
		q.push(S); dist[S] = 0;
		while(!q.empty()){
			int x = q.front(); q.pop();
			for(int i = S;i<=T;++i)if(cap[x][i] > 0 && dist[i] == -1){
				dist[i] = dist[x] + 1;
				q.push(i);
			}
		}
		return (dist[T] >= 0);
	}
	
	ll Dinic(ll lim){
		S = 0, T = F * 2 + 1;
		
		for(int i = S;i<=T;++i)
			for(int j = S;j<=T;++j)cap[i][j] = -1;
			
		for(int i = 1;i<=F;++i){
			addedge(S,i,cow[i]);
			addedge(i+F,T,pen[i]);
			for(int j = 1;j<=F;++j)
				if(dis[i][j] <= lim)addedge(i,j+F,inf);
		}
		
		ll ans = 0;
		while(bfs()){
			while(1){
				ll flow = dfs(S,inf);
				if(flow == 0)break;
				ans += flow;
			}
		}
		return ans;
	}
}
using namespace Net;

图论建模

P3254圆桌问题

basic

套路地,将人看作“流水”,那么我们可以通过人数的流向具象化桌子与单位之间的关系。具体做法:

每一个单位作为一个点,每一个桌子看作一个点,源点 \(S\) 向每一个单位 \(i\) 连一条权值为 \(r[i]\) 的边,每一个桌子 \(i\) 向汇点连一条权值为 \(c[i]\) 的边。这样我们看所有人是否可以都入座就是看最大流是不是等于总人数。

对于中间的,由于题目条件“同一个单位来的代表不在同一个餐桌就餐”,因此,每一个单位向每一个餐桌连一条权值为 \(1\) 的有向边。

方案就是去看看对于一条 单位->桌子 的边,跑完后这条边的剩余容量是否为 \(0\),若是,则表明这一条边有人选择。

scanf("%d%d",&m,&n);
S = 0, T = m + n + 1;
for(int i = 1;i<=m;++i){
	scanf("%d",&r[i]);
	addedge(S,i,r[i]);
	cnt += r[i];
}
for(int i = 1;i<=n;++i){
	scanf("%d",&c[i]);
	addedge(i+m,T,c[i]);
}
for(int i = 1;i<=m;++i)
	for(int j = m+1;j<=m+n;++j)
		addedge(i,j,1);
int res = Dinic();
if(res != cnt)return puts("0"),0;
puts("1");
for(int i = 1;i<=m;++i){
	for(int j = head[i];j;j = edge[j].nxt){
		int v = edge[j].v - m;
		if(edge[j].cap == 0)printf("%d ",v);
	}
	puts("");
}

P6768 [USACO05MAR] Ombrophobic Bovines 发抖的牛

二分

要求最小时间,明显符合单调性,故二分答案。

与上题类似,将牛作为“水流”。

建图:

  1. S->每一个田地(代表这个田地的牛),边权为该位置牛的数量
  2. 每一个田地(代表这个田地的牛棚)->T,边权为牛棚容量
  3. 对于在二分的 \(mid\) 时间内可以到达的位置,连出一条权值为 \(inf\) 的边,因为“路很宽,无限量的牛可以通过”。

观察到数据范围很小,最短路可以用 Floyed 处理。

ll Dinic(ll lim){
	S = 0, T = F * 2 + 1;
	for(int i = S;i<=T;++i)
		for(int j = S;j<=T;++j)cap[i][j] = -1;
	for(int i = 1;i<=F;++i){
		addedge(S,i,cow[i]);
		addedge(i+F,T,pen[i]);
		for(int j = 1;j<=F;++j)
			if(dis[i][j] <= lim)addedge(i,j+F,inf);
	}
	ll ans = 0;
	while(bfs()){
		while(1){
			ll flow = dfs(S,inf);
			if(flow == 0)break;
			ans += flow;
		}
	}
	return ans;
}

P2891 [USACO07OPEN] Dining G

拆点

由于“每头牛只享用一种食物和一种饮料”,我们直接 S->食物->牛->饮料->T 的思路是错误的。

那么我们应当利用网络流中边的限定功能。

考虑拆点,一只牛被拆成了两个点,两点间连了一条权值为 \(1\) 的边,这样就可以保证一只牛只吃一对了。

拆点是个好东西!

S = 0, T = 2 * n + F + D + 1;
for(int i = 1;i<=F;++i)addedge(S,i,1);
for(int i = 2*n+F+1;i<=2*n+F+D;++i)addedge(i,T,1);
for(int i = 1;i<=n;++i)addedge(F+i,F+i+n,1);
for(int i = 1,a,b;i<=n;++i){
	scanf("%d%d",&a,&b);
	// cow_i F+i->F+i+n
	for(int j = 1,x;j<=a;++j){
		scanf("%d",&x);
		addedge(x,F+i,1);
	}
	for(int j = 1,x;j<=b;++j){
		scanf("%d",&x);
		addedge(F+i+n,2*n+F+x,1);
	}
}
printf("%d",Dinic());

P3191 [HNOI2007] 紧急疏散EVACUATE

二分 + 拆点

标签:tmp,return,补充,ll,cap,笔记,学习,int,edge
From: https://www.cnblogs.com/fight-for-humanity/p/18349804

相关文章

  • C语言学习
    学习内容一维数组,二维数组创建,初始化,数组名代码笔记#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>//一维数组//数组的创建//数组:相同元素类型的集合//数组的创建方式//typt_t  arr_name [const_n];//元素类型       常量表达式,用来指......
  • maven学习第一天
    核心功能依赖管理1.提取版本号统一管理在property标签内添加技术名.version如下图然后在依赖标签内写入如下格式即可2.引入依赖作用域在scop标签内定义依赖范围,默认的作用范围为compile3.依赖传递和冲突概念如下:依赖传递和依赖冲突常见的问题依赖传递常见的下载......
  • freertos学习笔记(十)事件标志组
    事件标志组相当于用户平时定义的Flag,事件标志,不过freertos支持将该标志组作为启动task的条件概述分为8位和24位的模式(通过设置宏来配置)每一位有0和1两个状态用法用于平常程序的标记位用于task之间的同步任务a先到达同步点,进入阻塞态设置任务a的事件标记位检查其......
  • 学习日常:造数据 - 上
    前言上次自己造数据,感悟颇丰,今天就来写一下这个话题。陈老师将这个任务交给我们时,给了我们一个板子,姑且叫它build_data.cpp:/*测试数据生成说明:1.本文件放入标程同文件夹2.在标程内贴入右边语句(不要修改):freopen("data.in","r",stdin);freopen("data.out","w",stdout);3.......
  • 轮换挑选图片,补充 es6的对象写法,uniapp使用,class和style,条件渲染,列表渲染,input
    Ⅰ轮换挑选图片【一】方式一<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title><scriptsrc="./js2/vue.js"></script></head><body>......
  • br4gOnB4ll靶机笔记
    br4gOnB4ll靶机笔记这是一台vulnhub上的免费靶机,比较简单。1、主机发现主机发现-sn只做ping扫描,不做端口扫描nmap-sn192.168.84.1/24StartingNmap7.93(https://nmap.org)at2024-07-0707:37EDTNmapscanreportfor192.168.84.1Hostisup(0.00045slatenc......
  • BossPlayersCTF靶机笔记
    BossPlayersCTF靶机靶机概述这是vulnhub上的一个简单的linux靶机,适合初级渗透测试人员,同时也告诉我们在渗透测试过程中要有耐心,要允许有兔子洞。靶机整体思路:主机端口探测,发现web服务。在web服务中进行信息收集,发现命令注入,反弹shell利用SUID进行提权,拿到rootflag靶机下......
  • 知攻善防Web1应急靶机笔记--详解
    知攻善防Web1应急靶机笔记概述这是一台知攻善防实验室的应急响应靶机,方便大家练习一下应急响应的流程和操作。靶机的前景概述:前景需要:小李在值守的过程中,发现有CPU占用飙升,出于胆子小,就立刻将服务器关机,这是他的服务器系统,请你找出以下内容,并作为通关条件:1.攻击者的shell密......
  • Redis学习笔记_1_基本安装与使用
    Redis入门篇1初识RedisRedis是一种键值型的NoSql数据库键值型:指Redis中存储的数据都是以key、value对的形式存储,而value的形式多种多样,可以是字符串、数值、甚至jsonNoSql:相对于传统关系型数据库而言,有较大差异1.1认识NoSQLNoSql可以翻译做NotOnlySql(不仅仅是SQL......
  • 基于YOLOv10深度学习的交通信号灯检测识别系统【python源码+Pyqt5界面+数据集+训练代
    《博主简介》小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~......