HDU 3038 - How Many Answers Are Wrong (并查集)

题目传送

分析:
因为要判断正误,最直接的为 a == a,b == b,c != c,可以判断语句错误,但大多数情况不能直接判断,就需要转换,例如:1-5=5,6-10=10,1-10=8,根据这三个语句就可以判断有一个错误。题目给出的是闭区间,可以转换为左开右闭区间,就可以运用(a,b]+(b,c]=(a,c],令par[x]为x到根的距离,当ab不同根时,以a的根作为b的根的根,par[r2]=par[a]+c-par[b].若ab同根,则par[b]-par[a]就为ab的距离。

int find(int x)
{
	if (par[x] == x) return x;
	int ret = find(par[x]);
	val[x] += val[par[x]];
	return par[x] = ret;
}

当时一直wa,后来发现是着出的问题。
wa代码:

 /*
    if (par[x] == x) return x;
	val[x] += val[par[x]];
	return par[x] = find(par[x]);
 */

后来仔细想了一下,递归find(par[x])的过程中,par[x]的根会更新,所以要先递归,记录下答案。

完整代码附上:

#include <iostream>
using namespace std;

const int maxn = 2e5 + 10;

int par[maxn];
int val[maxn];

void init(int n)
{
	for (int i = 0; i <= n; i++) {
		par[i] = i;
		val[i] = 0;
	}
	return;
}

int find(int x)
{
	if (par[x] == x) return x;
	int ret = find(par[x]);
	val[x] += val[par[x]];
	return par[x] = ret;
	/*if (par[x] == x) return x;
	val[x] += val[par[x]];
	return par[x] = find(par[x]);
	*/
}

int main(void)
{
	int n, m;
	while (cin >> n >> m) {
		int ans = 0;
		init(n);
		for (int i = 0; i < m; i++) {
			int a, b, c;
			cin >> a >> b >> c;
			a--;
			int r1 = find(a);
			int r2 = find(b);
			if (r1 != r2) {
				par[r2] = r1;
				val[r2] = val[a] + c - val[b];
			}
			else {
				if (val[b] - val[a] != c) {
					ans++;
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}
发布了16 篇原创文章 · 获赞 9 · 访问量 4563

猜你喜欢

转载自blog.csdn.net/qq_43054573/article/details/104254699