[AtCoder Beginner Contest 396] E - Min of Restricted Sum
题目描述
题目链接
方法 BFS + 位运算
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
vector<PII> g[N];
bool visited[N];
LL val[N];
LL ans[N];
vector<int> BFS(int start) {
queue<int> q;
q.push(start);
visited[start] = true;
vector<int> a = {start};
val[start] = 0;
while(! q.empty()) {
int v = q.front();
q.pop();
for (auto [u, w] : g[v]) {
if (! visited[u]) {
visited[u] = true;
val[u] = val[v] ^ w;
a.pb(u);
q.push(u);
} else {
if (val[u] != (val[v] ^ w)) {
cout << -1 << '\n';
exit(0);
}
}
}
}
return a;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
memset(val, -1, sizeof(val));
//用图存储节点信息
for (int i = 0; i < m; i ++) {
int x, y, z;
cin >> x >> y >> z;
x--, y--;
g[x].pb({y, z});
g[y].pb({x, z});
}
for (int st = 0; st < n; st ++) {
if (visited[st]) continue;
vector<int> a = BFS(st);
//1e9 < 2 ^ 30,所以考虑最多右移29位
for (int i = 0; i < 30; i ++) {
int cnt = 0;
LL mask = (LL) 1 << i;
//统计在这个集合中第i位为1的数量
for (int j : a) {
if (val[j] >> i & 1) cnt ++;
}
//下面的操作可以保证异或的约束条件不会被破坏,并选出尽可能少的1,从而使和最小
//如果在该集合中第i位为1的数量小于为0的数量
if (cnt < a.size() - cnt) {
for (int j : a) {
if (val[j] >> i & 1) {
ans[j] |= mask;
}
}
} else { //如果在该集合中第i位为1的数量大于等于为0的数量, 则把为0的ans[j]的第i位置为1
for (int j : a) {
if (! (val[j] >> i & 1)) {
ans[j] |= mask;
}
}
}
}
}
for (int i = 0; i < n; i ++) {
cout << ans[i] << " ";
}
cout << '\n';
return 0;
}