Description
Theofanis started playing the new online game called “Among them”.
However, he always plays with Cypriot players, and they all have the
same name: “Andreas” (the most common name in Cyprus).In each game,
Theofanis plays with n n n other players. Since they all have the same
name, they are numbered from 1 1 1 to n n n.The players write m m m comments
in the chat. A comment has the structure of " i i i j j j c c c" where i i i
and j j j are two distinct integers and c c c is a string ( 1 ≤ i , j ≤ n 1 \le i, j \le n 1≤i,j≤n; i ≠ j i \neq j i=j; c c c is either imposter or crewmate). The comment means
that player i i i said that player j j j has the role c c c.An imposter
always lies, and a crewmate always tells the truth. Help Theofanis
find the maximum possible number of imposters among all the other
Cypriot players, or determine that the comments contradict each other
(see the notes for further explanation).Note that each player has
exactly one role: either imposter or crewmate.
Input
The first line contains a single integer t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104) — the number of test cases. Description of each test case follows.The first line of each test case contains two integers n n n and m m m ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105; 0 ≤ m ≤ 5 ⋅ 1 0 5 0 \le m \le 5 \cdot 10^5 0≤m≤5⋅105) — the number of players except Theofanis and the number of comments.Each of the next m m m lines contains a comment made by the players of the structure " i i i j j j c c c" where i i i and j j j are two distinct integers and c c c is a string ( 1 ≤ i , j ≤ n 1 \le i, j \le n 1≤i,j≤n; i ≠ j i \neq j i=j; c c c is either imposter or crewmate).There can be multiple comments for the same pair of ( i , j ) (i, j) (i,j).It is guaranteed that the sum of all n n n does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 and the sum of all m m m does not exceed 5 ⋅ 1 0 5 5 \cdot 10^5 5⋅105.
Output
For each test case, print one integer — the maximum possible number of imposters. If the comments contradict each other, print − 1 -1 −1.
1 建图
利用二分图的思想,把一个命题拆成 对 和 错 两个点,即 u 点表示 u 为真,u+n 点表示 u 为假。
显然,如果出现一条 u -> u+n 的边,则产生矛盾,这可以直接使用并查集判断。
根据题意,如果 u 指定 v 为 imposter ,则若 u 为 imposter ,v为 crewmate ,反之亦然。
while (m--)
{
cin >> u >> v >> s;
if (s == "imposter")
{
//无向图
g[u].push_back(v + n);
g[v + n].push_back(u);
g[v].push_back(u + n);
g[u + n].push_back(v);
//并查集判断逻辑链上是否冲突
Union(u, v + n);
Union(v, u + n);
}
else
{
g[u].push_back(v);
g[v].push_back(u);
g[v + n].push_back(u + n);
g[u + n].push_back(v + n);
Union(u, v);
Union(u + n, v + n);
}
}
2 DFS
在保证每一条逻辑链不发生冲突之后。我们可以将图看成一些逻辑链的集合。这些链将是独立并且逻辑自洽的。
我们遍历每一条链,记录链上的 imposter 数量 cnt 和链的深度 res,则有两种情况。如果这条链是真的(即链上的 imposter 确实是 imposter) ,则这条链上的 imposter 数量为 cnt,如果这条链是假的,则这条链上的 imposter 数量为 res - cnt 。对每条链取它们的最大值,相加得到答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
#define all(x) x.begin(), x.end()
#define maxi(x) max_element(x.begin(), x.end()) - x.begin()
#define mini(x) min_element(x.begin(), x.end()) - x.begin()
#define cmax(x, y) x = max(x, y)
#define cmin(x, y) x = min(x, y)
const int maxn = 5e5 + 10;
vector<vector<int>> g;
int idx, f[maxn], cnt;
bool st[maxn];
int n, m, u, v;
string s;
int find(int x)
{
if (x == f[x])
return x;
return f[x] = find(f[x]);
}
void Union(int a, int b)
{
a = find(a);
b = find(b);
if (a != b)
f[a] = b;
}
int dfs(int u, int fa)
{
if (st[u])
return 0;
st[u] = 1;
if (u > n)
cnt++;
int res = 1;
for (auto v : g[u])
{
if (v == fa)
continue;
res += dfs(v, u);
}
return res;
}
void init()
{
g.clear();
g.resize(2 * n + 1);
for (int i = 1; i <= 2 * n + 1; i++)
f[i] = i, st[i] = 0;
}
void solve()
{
cin >> n >> m;
init();
while (m--)
{
cin >> u >> v >> s;
if (s == "imposter")
{
g[u].push_back(v + n);
g[v + n].push_back(u);
g[v].push_back(u + n);
g[u + n].push_back(v);
Union(u, v + n);
Union(v, u + n);
}
else
{
g[u].push_back(v);
g[v].push_back(u);
g[v + n].push_back(u + n);
g[u + n].push_back(v + n);
Union(u, v);
Union(u + n, v + n);
}
}
for (int i = 1; i <= n; i++)
if (find(i) == find(i + n))
{
cout << -1 << endl;
return;
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
cnt = 0;
if (!st[i] && !st[i + n])
{
int x = dfs(i, -1);
ans += max(cnt, x - cnt);
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}