0
点赞
收藏
分享

微信扫一扫

CF366D Dima and Trap Graph 题解

爱动漫建模 2022-03-19 阅读 42
c++图论

题意

给定一张有 n n n 个节点, m m m 条边的无向图(可能有环或重边),对于每个节点 i i i,有 l i l_i li r i r_i ri,定义在经过该节点后,只能携带于 l i l_i li r i r_i ri 之间的数。

从编号为 1 的节点出发(初始时携带了所有自然数),到达编号为 n n n 的节点,求最后能携带最多的节点。

若节点数相同,输出字典序小的那一组。

若节点数为 0,输出 Nice work, Dima!

题解

模拟赛的一道题。

二分 + 图。

二分本质:

在数轴上找到一个临界点,即点的左边都可以满足条件,右边都不可以满足条件(或左边不可以,右边可以)。

在这道题中,r 值是有单调性的。即有一临界点,使得比它小的 r 值无法满足,比它大的 r 值可以满足。

但是,l 不具有单调性。例如,当 l 值为 1 时可以满足,l 值为 5 时可以满足,但是 l 值为 3 时能否满足是无法直接断定的。

所以,r 的值可以通过二分得到,l 的值只能枚举而得。

以上是思路。

但实现的时候我们可以用并查集优化:

我们从小到大枚举 l 的值,在此基础上,我们按 r 的值从大到小枚举每一条边。

保证每一条使用了的边的 e i . l e_i.l ei.l 的值比当前枚举的 l 的值小。

这里就运用了二分的思想。

每用一条边,就用并查集维护,如果 f 1 = f n f_1 = f_n f1=fn,就记录答案,最终输出最佳答案即可。

代码

#include<bits/stdc++.h>
using namespace std;

#define rint register int
const int inf = 1e6 + 5, maxn = 1005;
int n, m;
int cnt, hd[maxn];
struct node{
	int s, t;
	int l, r;
}e[maxn * 4];
int f[maxn];
int ansl, num;
int recl[maxn * 4];

inline int read ()
{
	int x = 1, s = 0;
	char ch = getchar ();
	while (ch < '0' or ch > '9'){if (ch == '-') x = -1; ch = getchar ();}
	while (ch >= '0' and ch <= '9') s = s * 10 + ch - '0', ch = getchar ();
	return x * s;
}

inline bool cmp (node a, node b)
{
	return a.r == b.r ? a.l < b.l : a.r > b.r;
}

inline void init ()
{
	for (rint i (1); i <= n; ++i) f[i] = i;
}

inline int find (int x)
{
	return f[x] == x ? x : find (f[x]);
}

int main ()
{
	n = read (), m = read ();
	for (rint i (1); i <= m; ++i) e[i].s = read (), e[i].t = read (), e[i].l = read (), e[i].r = read (), recl[i] = e[i].l;
	sort (e + 1, e + m + 1, cmp);
	sort (recl + 1, recl + m + 1);
	for (rint i (1); i <= m; ++i)
	{
		init ();
		bool flag = 0;
		int tl = recl[i], tr = inf;
		for (rint j (1); j <= m; ++j)
		{
			if (e[j].l > tl) continue;
			int u = find (e[j].s), v = find (e[j].t);
			if (u != v)
			{
				f[u] = v;
				tr = min (tr, e[j].r);
				if (find (1) == find (n)) 
				{
					flag = 1;
					break;
				}
			}
		}
		if (flag and num < tr - tl + 1) ansl = tl, num = tr - tl + 1;
	}
	if (num == 0)
	{
		printf ("Nice work, Dima!");
		return 0;
	}
	printf ("%d\n", num);
	return 0;
}
举报

相关推荐

0 条评论