(2021ICPC沈阳)(位运算+图论)Bitwise Exclusive-OR Sequence

      这道题也是翻阅了好多篇博客才将题目的做法搞懂,哈哈哈有些博主觉得它这道题算签到题,但作为蒻稷的ICPC小白觉得这道题非常有意思,非常值得一做。把一道这样的题搞懂也是挺有成就感的,我们队在之前见到这道题的时候一点头绪也没有,因为平时图论题做的少,也只能隐隐约约感觉这是一道位运算结合二分图的题目。而且对于我来说位运算的题目也做的很少,后面也是应该多去找找这种题目去练练。

        题目要求是给你n个数,m个限制,在符合每两位置异或对满足要求的情况下,使每一位的数值相加之和最小。画图分析样例之后可以得知在限制的情况下某几个节点将会组成一个子图联通分量,整个大的图中便有一个或者若干个联通分量,各个分量的最小相加即为最后答案。

        异或因为是有这样的一种性质  即:

                (a^b)^b=a        

                        a1^a2=w1

                        a2^a3=w2

                        a3^a4=w3

                        ........

                an=a1^w1^w2^w3^w4.......^wn;

                同时有个小结论,若干个1若干0异或,当1的个数是奇数那么最后异或结果是1,若是偶数或者是0的话,那么结果是0;

         所以在我们确认第一位的取值之后我们就可以遍历整个联通分量,并且知道联通分量中的每一个点的权值,我们将其次权值记录下,若题目给出的测试数据在遍历的时候产生矛盾,那么输出-1,若没有产生矛盾,则我们将每个点的权值进行储存,在遍历完此连通分量之后,我们调整各个点权值二进制的每一位的1或者0的个数。这个地方是不容易想到的,我们要保证此联通分量的值最小,那么我们要保证在每个点的权值二进制的每一位的1的个数加起来是最小的。若最后结果

        每点权值的这一位分别是 0 1 1 1 0, 那么我们为了保证每一位异或结果不变,我们也是将其调整为1 0 0 0 1.那么最后结果也会比之前小。发现这个之后我们直接上代码!

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,M=4e5+10;//这里不知咋回事开1e5过不了
int n,m;
int h[N],e[M],ne[M],w[M],idx=0;
int c[N];int vis[N];
//使用邻接表储存最后结果
int add(int a,int b,int c)
{
	w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
long long res=0;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)vis[i]=0,h[i]=-1;
	for(int i=1;i<=m;i++)
	{
		int a,b,c;cin>>a>>b>>c;
		add(a,b,c);
		add(b,a,c);
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i])continue;
		queue<int>q;vector<int>v;v.clear();
		q.push(i);vis[i]=1;
		c[i]=0;v.push_back(i);
		while(q.size())
		{
			int p=q.front();q.pop();
			for(int t=h[p];~t;t=ne[t])
			{
				int node=e[t];int vv=w[t];
				                      
      if(vis[node]==0)c[node]=c[p]^vv,v.push_back(node),vis[node]=1,q.push(node);
				else if((c[node]^c[p])!=vv)
				{
					puts("-1");return 0;	
				}	
			}
		}	
		for(int j=0;j<30;j++)
		{
			int cnt=v.size(),one=0;
			int bit=1<<j;
			for(int k=0;k<v.size();k++)
			{
				if(bit&c[v[k]])one++;
			}
			res+=1LL*min(one,cnt-one)*bit;//每一位1的最小值乘以权值得最后结果。
		}
	}
	cout<<res<<endl;return 0;
 } 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值