N
N
N个人,
M
M
M句话。每一句话这样描述
(
U
,
V
,
W
)
(U,V,W)
(U,V,W)
U
U
U 认为
V
V
V 是
T
r
u
t
h
m
a
n
Truthman
Truthman或者
F
a
k
e
m
a
n
Fakeman
Fakeman
根据这
M
M
M句话求
T
r
u
t
h
m
a
n
Truthman
Truthman最多的一种情况,误解输出
−
1
-1
−1。
思路
一共有两种情况:
- U U U 认为 V V V 是 T r u t h m a n Truthman Truthman, U , V U,V U,V同时为真或同时为假。
- U U U 认为 V V V 是 F a k e m a n Fakeman Fakeman, U , V U,V U,V一人为真一人为假。
- 我么可以把同一类的人用并查集合到一起, 然后判断是否有解。
- 如何构造 T r u t h m a n Truthman Truthman最多的情况?我们可以在并查集中为每个人定义一个权值或者是标记,记录这个人是 T r u t h m a n Truthman Truthman还是 F a k e m a n Fakeman Fakeman,这样并查集就可以比较那个 T r u t h m a n Truthman Truthman的人多。
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
#define endl '\n'
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
using namespace std;
int vis[maxn<<1], sz[maxn<<1], pre[maxn<<1];
int ans[maxn], n, m;
int find (int x) {
return (x == pre[x]) ? x : pre[x] = find(pre[x]);
}
void join(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx == fy) return;
pre[fy] = fx;
sz[fx] += sz[fy];
}
void solve() {
for (int i = 1; i <= n; ++i) {
int fx = find(i);
int fy = find(i+n);
if (fx == fy) {
cout << -1 << endl;
return;
}
// 判断当前所在的并查集是否已经确定 Truth or Fake
if (vis[fx] == 0) {
// 根据并查集的权值确定属性
if (sz[fx] > sz[fy]) {
vis[fx] = 1;
vis[fy] = -1;
}else {
vis[fy] = 1;
vis[fx] = -1;
}
}
ans[i] = (vis[fx] == 1);
}
for (int i = 1; i <= n; ++i) {
cout << ans[i];
}
cout << endl;
}
int main () {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n*2; ++i) {
pre[i] = i;
sz[i] = (i <= n);
vis[i] = 0;
}
for (int i = 0, u,v,w; i < m; ++i) {
cin >> u >> v >> w;
// 合并同类人
if (w) {
join(u, v);
join(u+n, v+n);
}else {
join(u, v+n);
join(u+n, v);
}
}
solve();
}
return 0;
}