首页 > 其他分享 >230712 // 新知:网络流

230712 // 新知:网络流

时间:2023-07-20 14:55:05浏览次数:36  
标签:gs vis int 网络 return dep maxn 新知 230712

今天是弟弟的 10 岁生日,祝他以后不要成为一个臭学信息的。

Cindy,玩原玩的。我忘了叫什么什么酩,不玩原导致的。


概念认知

所谓咕咕咕……


A. 草地排水

http://222.180.160.110:1024/contest/3696/problem/1



B. 完美的牛栏 The Perfect Stall

http://222.180.160.110:1024/contest/3696/problem/2



C. 奶牛食品

http://222.180.160.110:1024/contest/3696/problem/3



A. 小行星

http://222.180.160.110:1024/contest/3821/problem/1

一次可以选择清一行或一列。

我们对于每个小行星 \((x, y)\),将第 \(x\) 行和第 \(y\) 列连边,则每行发出的边可只要选择该行即可清楚,每列同理。

故原问题转化为二分图的最小点覆盖,即最大匹配。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int inf = 1e18;
const int maxn = 2e3 + 5;
const int maxm = 3e4 + 5;
int tag, gs, gt;
int n, m, x, y, w, tot = 1;
int vis[maxn], now[maxn], dep[maxn];
int h[maxn], to[maxm], ne[maxm], tw[maxm];
inline int min(int x, int y) {
	return x < y ? x : y;
}
bool BFS(void) {
	std::fill(dep + 1, dep + n + 1, 0); 
	std::queue<int> q;
	dep[gs] = 1, vis[gs] = tag;
	q.push(gs), now[gs] = h[gs];
	while (!q.empty()) {
		int f = q.front();
		q.pop();
		for (int i = h[f]; i; i = ne[i]) {
			int v = to[i], w = tw[i];
			if (vis[v] == tag || w == 0)
				continue;
			vis[v] = tag, now[v] = h[v];
			dep[v] = dep[f] + 1, q.push(v);
			if (v == gt)
				return 1;
		}
	}
	return 0;
}
int findP(int x, int flow = inf) {
	if (x == gt)
		return flow;
	int rest = flow, i;
	for (i = now[x]; rest && i; i = ne[i]) {
		int v = to[i], w = tw[i];
		if (dep[v] != dep[x] + 1 || w == 0)
			continue;
		int t = findP(v, min(rest, w));
		if (t == 0)
			dep[v] = 0;
		rest -= t;
		tw[i] -= t, tw[i ^ 1] += t;
	}
	now[x] = i;
	return flow - rest;
}
inline int Dinic(void) {
	int res = 0;
	for (tag = 1; BFS(); ++tag) {
		int t = findP(gs);
		while (t) {
			res += t;
			t = findP(gs);
		}
	}
	return res;
}
inline void add(int x, int y, int w) {
	to[++tot] = y, tw[tot] = w;
	ne[tot] = h[x], h[x] = tot;
	return;
}
int main() {
	read(n), read(m);
	gs = 2 * n + 1, gt = gs + 1;
	for (int i = 1; i <= n; ++i)
		add(gs, i, 1), add(i, gs, 0);
	for (int i = n + 1; i <= 2 * n; ++i)
		add(i, gt, 1), add(gt, i, 0);
	while (m--) {
		read(x), read(y);
		add(x, y + n, 1), add(y + n, x, 0);
	}
	print(Dinic(), '\n');
	return 0;
}
} // namespace XSC062
#undef int

B. 秘密挤奶机

http://222.180.160.110:1024/contest/3821/problem/2

题目那么长,其实就是说要求找到从 1 到 N 的 \(T\) 条路径,每条边不能同时被两条路径包含。

显然题目具有单调性。我们二分最大边权,只添加边权小于等于 mid 的边并令双向剩余量为 1(这样每条边就只会被选一次),跑一遍 Dinic 即可得到答案。

不知道为什么如果把 vis 数组改成时间戳而非每次清空就过不了(我为什么会发现这种事情呢,哭哭)。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int inf = 1e18;
const int maxn = 2e3 + 5;
const int maxm = 8e4 + 5;
int  gs, gt;
bool vis[maxn];
int n, m, t, tot;
int l, mid, r, res;
int now[maxn], dep[maxn];
int x[maxm], y[maxm], w[maxm];
int h[maxn], to[maxm], ne[maxm], tw[maxm];
inline int min(int x, int y) {
	return x < y ? x : y;
}
inline int max(int x, int y) {
	return x > y ? x : y;
}
bool BFS(void) {
	std::fill(vis + 1, vis + n + 1, 0); 
	std::fill(dep + 1, dep + n + 1, 0); 
	std::queue<int> q;
	dep[gs] = 1, vis[gs] = 1;
	q.push(gs), now[gs] = h[gs];
	while (!q.empty()) {
		int f = q.front();
		q.pop();
		for (int i = h[f]; i; i = ne[i]) {
			int v = to[i], w = tw[i];
			if (vis[v]|| w == 0)
				continue;
			vis[v] = 1, now[v] = h[v];
			dep[v] = dep[f] + 1, q.push(v);
			if (v == gt)
				return 1;
		}
	}
	return 0;
}
int findP(int x, int flow = inf) {
	if (x == gt)
		return flow;
	int rest = flow, i;
	for (i = now[x]; rest && i; i = ne[i]) {
		int v = to[i], w = tw[i];
		if (dep[v] != dep[x] + 1 || w == 0)
			continue;
		int t = findP(v, min(rest, w));
		if (t == 0)
			dep[v] = 0;
		rest -= t;
		tw[i] -= t, tw[i ^ 1] += t;
	}
	now[x] = i;
	return flow - rest;
}
inline int Dinic(void) {
	int res = 0;
	for (; BFS();) {
		int t = findP(gs);
		while (t) {
			res += t;
			t = findP(gs);
		}
	}
	return res;
}
inline void Init(void) {
	tot = 1;
	for (int i = 1; i <= n; ++i)
		h[i] = 0;
	return;
}
inline void add(int x, int y, int w) {
	to[++tot] = y, tw[tot] = w;
	ne[tot] = h[x], h[x] = tot;
	return;
}
inline bool check(int p) {
	Init();
	for (int i = 1; i <= m; ++i) {
		if (w[i] <= p) {
			add(x[i], y[i], 1);
			add(y[i], x[i], 1); 
		}
	}
	int u = Dinic();
	return u >= t;
}
int main() {
	read(n), read(m), read(t);
	gs = 1, gt = n, l = inf, r = -inf;
	for (int i = 1; i <= m; ++i) {
		read(x[i]), read(y[i]), read(w[i]);
		l = min(l, w[i]), r = max(r, w[i]); 
	}
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) {
			r = mid - 1;
			res = mid;
		}
		else l = mid + 1;
	}
	print(res, '\n');
	return 0;
}
} // namespace XSC062
#undef int

C. 猪

http://222.180.160.110:1024/contest/3821/problem/3

因为改换猪的位置而带来的「继承」关系是问题的难点。

我们先按常规思路走,开大源点连每个猪圈,权值为猪圈内初始猪数;连猪圈和对应的人,权值为无穷大;开大汇点连每个人,权值为这个人要买的猪数。

一开始的思路是,对于每一个人,将他可以开门的猪圈进行两两之间连边,但这样时间复杂度会达到 \(\mathcal O(n\times m^2)\)。

所以我们转而考虑通过人之间的传递来进行「继承」操作。

对于一个人,若他能开某个门,将他和上一个能开这个门的人连边,这样继承关系就一条龙传下来了。

注意处理重边以防超时。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int inf = 1e18;
const int maxn = 2e3 + 5;
const int maxm = 8e4 + 5;
int gs, gt;
bool vis[maxn];
bool p[maxn][maxn];
int n, m, x, y, tot = 1;
int now[maxn], dep[maxn], la[maxn];
int h[maxn], to[maxm], ne[maxm], tw[maxm];
inline int min(int x, int y) {
	return x < y ? x : y;
}
inline int max(int x, int y) {
	return x > y ? x : y;
}
bool BFS(int n) {
	std::fill(vis + 1, vis + n + 1, 0); 
	std::fill(dep + 1, dep + n + 1, 0); 
	std::queue<int> q;
	dep[gs] = 1, vis[gs] = 1;
	q.push(gs), now[gs] = h[gs];
	while (!q.empty()) {
		int f = q.front();
		q.pop();
		for (int i = h[f]; i; i = ne[i]) {
			int v = to[i], w = tw[i];
			if (vis[v]|| w == 0)
				continue;
			vis[v] = 1, now[v] = h[v];
			dep[v] = dep[f] + 1, q.push(v);
			if (v == gt)
				return 1;
		}
	}
	return 0;
}
int findP(int x, int flow = inf) {
	if (x == gt)
		return flow;
	int rest = flow, i;
	for (i = now[x]; rest && i; i = ne[i]) {
		int v = to[i], w = tw[i];
		if (dep[v] != dep[x] + 1 || w == 0)
			continue;
		int t = findP(v, min(rest, w));
		if (t == 0)
			dep[v] = 0;
		rest -= t;
		tw[i] -= t, tw[i ^ 1] += t;
	}
	now[x] = i;
	return flow - rest;
}
inline int Dinic(int n) {
	int res = 0;
	for (; BFS(n);) {
		int t = findP(gs);
		while (t) {
			res += t;
			t = findP(gs);
		}
	}
	return res;
}
inline void add(int x, int y, int w) {
	to[++tot] = y, tw[tot] = w;
	ne[tot] = h[x], h[x] = tot;
	return;
}
int main() {
	read(m), read(n);
	gs = n + m + 1, gt = n + m + 2;
	for (int i = 1; i <= m; ++i) {
		read(x);
		add(gs, i + n, x);
		add(i + n, gs, 0);
	}
	for (int i = 1; i <= n; ++i) {
		read(x);
		while (x--) {
			read(y), y += n;
			if (la[y] && !p[i][la[y]]) {
				p[i][la[y]] = 1;
				p[la[y]][i] = 1;
				add(la[y], i, inf);
				add(i, la[y], 0);
			}
			add(y, i, inf), add(i, y, 0);
			la[y] = i;
		}
		read(x);
		add(i, gt, x), add(gt, i, 0);
	}
	print(Dinic(gt), '\n');
	return 0;
}
} // namespace XSC062
#undef int

标签:gs,vis,int,网络,return,dep,maxn,新知,230712
From: https://www.cnblogs.com/XSC062/p/17548925.html

相关文章

  • matlab怎么使用BP神经网络知乎
    使用BP神经网络解决二分类问题问题描述假设我们有一个数据集,其中包含一些二维点的坐标和它们对应的标签。我们想要训练一个神经网络来对新的点进行分类,即判断它们属于哪个类别。解决方案为了解决这个问题,我们可以使用BP神经网络。BP神经网络是一种经典的人工神经网络,通过反向传......
  • plc网络通信方案地址转换通讯处理器
    捷米特JM-ETH-NAT可以实现近似于NAT的跨网段地址转换的功能:即可将LAN1口所连接PLC的IP地址和端口号,映射到LAN2口任意IP地址和端口号;方便解决了现场设备无法修改IP地址和端口号的问题; 捷米特JM-ETH-NAT具备两路物理性接口,LAN1和LAN2口分别具备独立的局域网功能。其中LAN1口为......
  • 【Sword系列】第七届全国残疾人职业技能大赛样题-网络安全-Book
    前言凯撒密码是一种简单的替换密码,它将明文中的每个字母都替换成向右(或向左)移动固定数量个位置后的另一个字母。具体来说,如果使用的是向右移动n位的凯撒密码,那么字母A将替换成第n+1个字母(即B),字母B将替换成第n+2个字母(即C),以此类推,字母Z将替换成第n个字母(即A)。对于......
  • 深度学习(七)——神经网络的卷积操作
    卷积操作一、torch.nn中ConvolutionLayers函数的介绍1.参数介绍nn.Conv1d:Conv取自Convolution的前四个字母,1d代表的是一个一维操作。nn.Conv2d:2d表示是一个二维的操作,比如图像就是一个二维的。其余参数不常用,见官网文档:torch.nn—PyTorch2.0documentation......
  • 单层反馈神经网络
    如何实现单层反馈神经网络简介单层反馈神经网络(Single-layerFeedforwardNeuralNetwork)是一种最简单的神经网络模型,也叫感知机(Perceptron)。它由输入层、输出层和一个称为激活函数的非线性函数组成,可以用于二分类或多分类问题。本文将介绍如何使用Python实现单层反馈神经网络。......
  • vm 因为部分网络问题ping不通虚拟机,虚拟机也上不了网的经历
    主机连着公司wifi,wifi上网需要登录认证账号,此账号同时只能在线一个,不好办一网络适配器用vmnet0,桥接到wifi网卡,能ping通了,但是总是断,ssh一小会就断。ip尝试过静态、动态都不行二适配器vmnet8网络的nat模式,ping不通,vm8网络-属性-配置里图中改成enable。不行。后来ping通了改回diabled......
  • 神经网络与机器学习邱锡鹏
    如何实现神经网络与机器学习邱锡鹏作为一名经验丰富的开发者,我将以一种简洁明了的方式来教会你如何实现"神经网络与机器学习邱锡鹏"。下面是整个流程的步骤概述:步骤说明1.数据准备收集、清洗和准备数据2.特征工程对数据进行预处理和特征提取3.神经网络建模......
  • 神经网络结构图工具
    如何实现神经网络结构图工具作为一名经验丰富的开发者,我很高兴能够教会你如何实现一个神经网络结构图工具。在本文中,我将为你提供一个详细的步骤,以及每一步需要做什么和相应的代码示例。让我们开始吧!步骤一:项目初始化首先,我们需要创建一个新的Python项目,并初始化一个虚拟环境来......
  • 神经网络降噪演示
    神经网络降噪演示介绍神经网络降噪是一种常用的图像处理技术,通过训练神经网络来去除图像中的噪声。本文将介绍神经网络降噪的原理,并通过一个代码示例演示如何使用Python实现神经网络降噪。原理神经网络降噪通常包括两个步骤:训练和应用。在训练阶段,我们使用一组带有噪声的图像......
  • 神经网络分类模型
    神经网络分类模型神经网络是一种模仿人类神经系统构造的人工智能模型。它由多个神经元组成的层级结构,每个神经元通过输入信号的加权和进行激活,传递给下一层的神经元。神经网络模型可以用于各种机器学习任务,包括分类、回归和聚类等。本文将重点介绍神经网络在分类任务中的应用,并提......