扩展域并查集Codeforces Round #747 (Div. 2) D. The Number of Imposters
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扩展域并查集Codeforces Round #747 (Div. 2) D. The Number of Imposters相关的知识,希望对你有一定的参考价值。
题目链接:
https://codeforces.com/problemset/problem/1594/D
有 n 个人,每个人可能是诚实的人或者说谎的人。
诚实的人永远说真话,说谎的人永远说假话。
有 m 个条件,分别表示 i 说 j 是诚实的人/说谎的人。
你需要判断在这些限制条件下,最多有可能有几个诚实的人,或输出 -1 声明不可能存在这种情况。
分析规则:
- 若A说B诚实,则AB要么都诚实,要么都是骗子
- 若A说B骗子,则A诚实B骗子 ,或者A骗子B诚实
可以发现当一个人诚实和骗子确定下来,与他相关的人都会确定下来。
考虑用一个并查集进行维护,并查集开两倍的空间。
用x
表示表示一个人,则x
表示他诚实,x + n
表示他是骗子。所以并查集前半部分的空间开的是诚实的人的,后半部分开的是骗子的人的。
注意: 初始化时,只有前半部分的人的sz
数组初始化为1
,其余都为0
如果
f
i
n
d
(
x
)
=
=
f
i
n
d
(
x
+
n
)
find(x)==find(x+n)
find(x)==find(x+n),则会产生冲突,结果为-1
并查集中因为一正一反,如果有两种情况,那么这两种情况是相反的。用个图来理解
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int N = 1e5 + 5;
struct dsu
vector<int> f, sz;
dsu(int n)
f.resize(n);
sz.resize(n, 1);
for(int i = 1; i < n; i++) f[i] = i;
int find(int x)
return x == f[x] ? x : f[x] = find(f[x]);
void merge(int x, int y)
x = find(x);
y = find(y);
if(x == y) return;
if(sz[x] < sz[y]) swap(x, y);
f[y] = x;
sz[x] += sz[y];
sz[y] = 0;
;
void solve()
int n, m;
cin >> n >> m;
dsu tr(2 * n + 1);
for(int i = n + 1; i <= 2 * n; i++)
tr.sz[i] = 0;
for(int i =1; i <= m; i++)
int x, y;
string s;
cin >> x >> y >> s;
if(s[0] == 'c') tr.merge(x, y), tr.merge(x + n, y + n);
else tr.merge(x, y + n), tr.merge(x + n, y);
int res = 0;
for(int i = 1; i <= n; i++)
int x = tr.find(i), y = tr.find(i + n);
if(x == y)
cout << -1 << "\\n";
return;
res += max(tr.sz[x], tr.sz[y]);
tr.sz[x] = 0, tr.sz[y] = 0;
cout << res << "\\n";
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--) solve();
return 0;
以上是关于扩展域并查集Codeforces Round #747 (Div. 2) D. The Number of Imposters的主要内容,如果未能解决你的问题,请参考以下文章