题目描述:
让构造一个长度为n的数组,保证满足给定的m个约束,在满足条件的情况下给出最小值,若不满足输出-1
输入:n,m
接下来m行每行给u, v, w 意思是要求a[u] ^ a[v] = w;
对每个u,v,w 我们连一条权值为w的双向边
对于每个联通的图几个点来说 例如a1 -> a2 -> a3 -> a4
a2 = a1 ^ w1;
a3 = a2 ^ w2 = a1 ^ w1 ^ w2;
a4 = a3 ^ w3 = a1 ^ w1 ^ w2 ^ w3;
……以此类推
对于每个联通的几个点来说 要满足权值的和最小 只需考虑给定a1为多少即可
直接从a1开始DFS 对于每个点ai 我们可以直接求出此点的k1 即w1 ^ w2 ^……wi
对于每个点的ki 找每一位是否为1 即for(int i = 31; i >= 0;i--) if(k >> i & 1) f[i]++;
若此位为1 则说明在点ai 需要满足在此位上和a1取反(0 - 1, 1 - 0);
枚举出每个连通块中 每位需要取反的点的数量, 若需要取反的数量大于连通块点的数量的一半,则原来a1的该位为1,
反之a1的该位为0
最后根据每个点的值 跑一遍BFS看是否满足上述m个约束
下面是代码 实测跑得飞快
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 100010, M = 400010;
ll dist[N];
int h[N],e[M],ne[M],idx;
ll w[M];
int u[M],v[M];
int b[40];
ll ww[M];
bool st[N];
bool stt[N];
int n,m;
int cnt;
ll ans;
void add(int a, int b,ll c)
{
e[idx] = b ,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u,int fa,int k)
{
cnt++;
stt[u] = true;
if(fa == -1)
{
for(int i = h[u];i != -1;i = ne[i])
{
int j = e[i];
if(j == fa || stt[j]) continue;
int c = w[i];
dfs(j,u,c);
}
}
else
{
for(int i = 31;i>=0;i--)
{
if(k >> i & 1) b[i]++;
}
for(int i = h[u];i != -1;i = ne[i])
{
int j = e[i];
if(j == fa || stt[j]) continue;
int c = w[i];
int v = c ^ k;
dfs(j,u,v);
}
}
return;
}
void bfs(int u,int d)
{
dist[u] = d;
queue<int> q;
q.push(u);
st[u] = true;
while(q.size())
{
auto t = q.front();
ans += dist[t];
q.pop();
for(int i = h[t];i != -1; i = ne[i])
{
int j = e[i];
if(st[j]) continue;
st[j] = true;
dist[j] = dist[t] ^ w[i];
q.push(j);
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
memset(dist,0x3f,sizeof dist);
for(int i = 0;i < m;i++)
{
scanf("%d%d%lld",&u[i],&v[i],&ww[i]);
add(u[i],v[i],(ll)ww[i]), add(v[i],u[i],(ll)ww[i]);
}
for(int i = 1;i<=n;i++)
{
if(!st[i])
{
for(int k = 0;k <= 31;k++) b[k] = 0;
cnt = 0;
dfs(i,-1,0);
int d = 0;
for(int k = 31;k>=0;k--)
{
if(b[k] > cnt - b[k])
{
d += (1 << k);
}
}
bfs(i,d);
}
}
for(int i = 0;i <m;i++)
{
if((dist[u[i]] ^ dist[v[i]])!= ww[i])
{
ans = -1;
break;
}
}
cout << ans <<endl;
return 0;
}