冒牌货数量
二分图好题
题意:
-
有 n 个人,每个人身份只可能是 好人 或者 坏人。好人只说真话,坏人只说假话。
-
有 m 个言论, i 、 j 、 c i 、j、c i、j、c ,表示 i 人 说 j 人 是 好人 或者 坏人( 也就是 c )。
-
问给定的言论是否有冲突,如果没有冲突求 好人的最大数量
思路:
-
首先观察可以发现,当言论中 c 为 好人时,两方身份肯定一样,反之当言论 c 为 坏人时,两方身份相反。
-
一开始想用并查集处理冲突,但发现很难统计人数。 正解是神中神的 建造二分图。
-
如果两人身份不同就在他们之间连一条边(寓意相邻两点颜色不同)
-
反之如果两人身份相同,我们建一个虚点,让两点连接虚点(寓意两点不相邻颜色相同)。
-
显然最后我们只需要染色法判断这个图是不是二分图就可以知道有无冲突。如果无冲突,每个连通块记录最多的一种颜色即可。
C o d e : Code: Code:
#include<bits/stdc++.h>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define rfor(a,b,c) for(int a=b;a>=c;a--)
#define all(a) a.begin(),a.end()
#define oper(a) (operator<(const a& ee)const)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
double DNF = 1e17;
const int N = 700010, M = 1000010, MM = 110;
int INF = 0x3f3f3f3f, mod = 1e9 + 7;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D, K;
vector<int> e[N];
int color[N], a1, a2;
bool dfs(int x, int c) {
color[x] = c;
if (x <= n) { // 不要把虚点颜色算进去了
if (c == 1)a1++;
else a2++;
}
for (int j : e[x]) {
if (!color[j]) {
if (!dfs(j, 3 - c))return false;
}
else if (color[j] == color[x])return false;
}
return true;
}
void solve() {
cin >> n >> m;
forr(i, 1, n + m)e[i].clear(), color[i] = 0;
string c;
int a, b;
int n1 = n;
forr(i, 1, m) {
cin >> a >> b >> c;
if (c == "crewmate") {
int g = ++n1;//虚点
e[a].push_back(g), e[g].push_back(a);
e[g].push_back(b), e[b].push_back(g);
}
else {
e[a].push_back(b);
e[b].push_back(a);
}
}
int mx = 0;
forr(i, 1, n1)if (!color[i]) {
a1 = a2 = 0;
if (!dfs(i, 1)) { //判断冲突
cout << -1 << endl;
return;
}
mx += max(a1, a2);//每次累计最多的一种颜色
}
cout << mx << endl;
}
int main() {
cinios;
cin >> T;
while (T--)solve();
return 0;
}
/*
*/