SDOI2014 Lis(网络流)

本文介绍了一种使用最小割算法解决特定问题的方法,该问题要求找到删除节点的最小代价,同时保持解的字典序最小。通过按代价排序并检查每条边是否在割集中,结合退流技巧优化最大流计算,最终得到最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题目大意

题目已经说得很清楚了qwq。

题解

首先我们考虑如何计算出最少删除的代价。
考虑在dp的过程中,如果 i i i能够使 j j j取到最大值,就连边 ( i , j ) (i,j) (i,j),容易发现,题目就是问去掉一些点使左右不连通求最小代价。
于是拆点连边跑最小割即可。
但是题目还要字典序最小,我们考虑按C从小到大排序,判断当前边是否在割中,如果在,就割掉。然鹅我们必须及时更新每条边的剩余容量,因此每次割掉之后还要跑最大流。但是这样显然会T,于是就需要退流。
( u , v ) (u,v) (u,v)删掉后退流的过程就是跑 u → S u\rightarrow S uS的最大流,再跑 T → v T\rightarrow v Tv的最大流即可。
然后就过了。

#include <bits/stdc++.h>
using namespace std;
const int MAXR = 10000000;
char _READ_[MAXR], _PRINT_[MAXR];
int _READ_POS_, _PRINT_POS_, _READ_LEN_;
inline char readc() {
#ifndef ONLINE_JUDGE
	return getchar();
#endif
	if (!_READ_POS_) _READ_LEN_ = fread(_READ_, 1, MAXR, stdin);
	char c = _READ_[_READ_POS_++];
	if (_READ_POS_ == MAXR) _READ_POS_ = 0;
	if (_READ_POS_ > _READ_LEN_) return 0;
	return c;
}
template<typename T> inline void read(T &x) {
	x = 0; register int flag = 1, c;
	while (((c = readc()) < '0' || c > '9') && c != '-');
	if (c == '-') flag = -1; else x = c - '0';
	while ((c = readc()) >= '0' && c <= '9') x = x * 10 + c - '0';
	x *= flag;
}
template<typename T1, typename ...T2> inline void read(T1 &a, T2&... x) {
	read(a), read(x...);
}
inline int reads(char *s) {
	register int len = 0, c;
	while (isspace(c = readc()) || !c);
	s[len++] = c;
	while (!isspace(c = readc()) && c) s[len++] = c;
	s[len] = 0;
	return len;
}
inline void ioflush() { fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0; fflush(stdout); }
inline void printc(char c) {
	_PRINT_[_PRINT_POS_++] = c;
	if (_PRINT_POS_ == MAXR) ioflush();
}
inline void prints(char *s) {
	for (int i = 0; s[i]; i++) printc(s[i]);
}
template<typename T> inline void print(T x, char c = '\n') {
	if (x < 0) printc('-'), x = -x;
	if (x) {
		static char sta[20];
		register int tp = 0;
		for (; x; x /= 10) sta[tp++] = x % 10 + '0';
		while (tp > 0) printc(sta[--tp]);
	} else printc('0');
	printc(c);
}
template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {
	print(x, ' '), print(y...);
}
typedef long long ll;

const int MAXN = 2005, MAXM = 1000005, INF = 0x3f3f3f3f;
struct Edge { int to, cap, next; } edge[MAXM];
int head[MAXN], que[MAXN], dis[MAXN], vis[MAXN], tot;
void addedge(int u, int v, int c) {
	edge[tot] = (Edge) { v, c, head[u] };
	head[u] = tot++;
	edge[tot] = (Edge) { u, 0, head[v] };
	head[v] = tot++;
}
bool bfs(int s, int t) {
	int he = 0, ta = 0;
	memset(dis, -1, sizeof(dis));
	dis[que[ta++] = s] = 0;
	while (he < ta) {
		int u = que[he++];
		for (int i = head[u]; ~i; i = edge[i].next) {
			int v = edge[i].to;
			if (edge[i].cap && dis[v] < 0) {
				dis[que[ta++] = v] = dis[u] + 1;
				if (v == t) return 1;
			}
		}
	}
	return 0;
}
int dfs(int u, int t, int f) {
	if (u == t) return f;
	int flow = 0;
	for (int i = head[u]; ~i; i = edge[i].next) {
		int v = edge[i].to;
		if (edge[i].cap > 0 && dis[v] > dis[u]) {
			int d = dfs(v, t, min(f, edge[i].cap));
			if (d == 0) continue;
			f -= d, flow += d;
			edge[i].cap -= d, edge[i ^ 1].cap += d;
			if (f == 0) return flow;
		}
	}
	if (flow == 0) dis[u] = -1;
	return flow;
}
int dinic(int s, int t) {
	int flow = 0;
	while (bfs(s, t)) flow += dfs(s, t, INF);
	return flow;
}
int A[MAXN], B[MAXN], C[MAXN], f[MAXN], arr[MAXN], n, T;
bool cmp(int x, int y) { return C[x] < C[y]; }
void cut(int x) {
	for (int i = head[x * 2 - 1]; ~i; i = edge[i].next)
		if (edge[i].to == x * 2) edge[i].cap = edge[i ^ 1].cap = 0;
}
int main() {
	for (read(T); T--;) {
		read(n);
		memset(head, -1, sizeof(head)); tot = 0;
		for (int i = 1; i <= n; i++) read(A[i]);
		for (int i = 1; i <= n; i++) read(B[i]);
		for (int i = 1; i <= n; i++) read(C[i]);
		int s = n * 2 + 1, t = s + 1, mx = 0;
		for (int i = 1; i <= n; i++) {
			f[i] = 1;
			for (int j = 1; j < i; j++)
				if (A[j] < A[i]) f[i] = max(f[i], f[j] + 1);
			for (int j = 1; j < i; j++)
				if (A[j] < A[i] && f[j] + 1 == f[i]) addedge(j * 2, i * 2 - 1, INF);
			addedge(i * 2 - 1, i * 2, B[i]);
			if (f[i] == 1) addedge(s, i * 2 - 1, INF);
			mx = max(mx, f[i]);
		}
		for (int i = 1; i <= n; i++) if (f[i] == mx) addedge(i * 2, t, INF);
		print(dinic(s, t), ' ');
		for (int i = 1; i <= n; i++) arr[i] = i;
		sort(arr + 1, arr + 1 + n, cmp);
		vector<int> ans;
		for (int i = 1; i <= n; i++) {
			int x = arr[i];
			if (bfs(x * 2 - 1, x * 2)) continue;
			cut(x), dinic(x * 2 - 1, s), dinic(t, x * 2);
			ans.push_back(x);
		}
		print(ans.size());
		sort(ans.begin(), ans.end());
		for (int i : ans) print(i, ' ');
		printc('\n');
	}
	ioflush();
	return 0;
}
### 回答1: LIS网络端口测试工具是一款用于检测网络中主机端口状态的工具。它可以帮助网络管理员快速定位网络故障,并且提供了简单易用的界面和丰富的功能。 这款工具可以通过选择不同的协议(如TCP、UDP、HTTP等)和输入目标主机的IP地址以及端口号,来测试目标主机上特定端口是否可达。通过向目标主机发送数据包,并根据响应情况来判断目标端口的状态,如是否开放、关闭或过滤等。 LIS网络端口测试工具还提供了一些高级功能,如可以自定义数据包的内容、发送频率、超时时间等,并支持对多个端口进行批量测试,提高了测试效率。同时,它还能够显示测试结果的详细信息,比如响应时间、数据包丢失率等,方便用户进行故障排查和分析。 除了简单的端口测试功能外,LIS网络端口测试工具还具备了其他扩展功能,如支持IP和域名的解析、支持更高级的协议测试(如SMTP、FTP等),以及提供了一些网络诊断工具,如Ping、Traceroute等。 总而言之,LIS网络端口测试工具是一款实用的网络工具,它可以帮助网络管理员检测和排查网络故障,提供了丰富的功能和简洁的界面,是网络管理人员必备的工具之一。 ### 回答2: Lis网络端口测试工具是一款用于测试网络端口是否开放的工具。在网络通信中,设备之间通过端口进行数据传输,端口是设备上的一个逻辑入口,用于识别不同的服务或应用程序。而网络端口测试的目的就是通过向特定端口发送数据包,确定该端口是否能够正常接收和响应数据。 Lis网络端口测试工具提供了一种简单、直观的方式来进行端口测试。用户只需在工具中输入目标IP地址和要测试的端口号,然后点击测试按钮即可开始测试。工具会向目标设备的指定端口发送一个测试数据包,并等待目标设备的响应。 通过测试工具的测试结果,可以得知目标设备上特定端口是否开放。如果测试结果显示端口开放,则说明目标设备上的该端口可以接受数据,并且可以与该端口上的服务或应用进行通信。而如果测试结果显示端口关闭,则说明目标设备上的该端口无法正常接受数据。 Lis网络端口测试工具可以帮助网络管理员和系统工程师快速了解网络设备的端口状态,确保网络通信的正常运行。无论是在日常网络维护中,还是在网络安全测试中,都可以使用这款工具进行端口测试,以便及时发现和解决端口相关的问题。 总之,Lis网络端口测试工具是一款方便实用的工具,可以帮助用户进行网络端口的快速测试和诊断,提高网络运行的效率和安全性。 ### 回答3: Lis网络端口测试工具是一种用于检测网络中开放端口情况的软件工具。它可以帮助网络管理员或安全专家快速、准确地识别网络中的开放端口,从而评估网络的安全性和弱点。通常,它可以通过发送特定协议的数据包来测试目标设备的端口是否开放或关闭。 在使用Lis网络端口测试工具时,用户首先需要指定目标设备的IP地址和端口号。然后,工具会按照指定的端口范围或特定端口进行扫描。扫描完成后,工具会生成一份报告,显示目标设备开放和关闭的端口情况。报告通常包含端口号、端口状态(开放或关闭)、所使用的协议和服务等信息。用户可以利用这些信息判断网络设备的安全性和配置问题,进一步加强网络的防护措施。 Lis网络端口测试工具的优势在于其简单易用,同时具备高效、准确的端口扫描能力。它可以快速发现网络中的被攻击风险,帮助用户及时采取行动加强网络安全。此外,Lis工具还支持自定义扫描参数,用户可以根据自己的需求进行扫描设置,提高工作的灵活性。 总结来说,Lis网络端口测试工具是一种功能强大、易于使用的工具,用于评估网络设备的安全性和识别可能的漏洞。通过使用该工具,用户可以提前发现潜在的网络风险,并采取相应的措施来保护网络安全。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值