牛客 - 建通道(思维)

题目链接:点击查看

题目大意:给出每个点的权值为v[ i ],现在要求将 n 个点互相连通,以保证代价最小,点 i 和点 j 连接的代价为 lowbit( v[ i ] ^ v[ j ])

题目分析:挺简单的一道思维题吧,比赛的时候最后开的这个题目,时间不太多了,心态也比较浮躁,导致没有发挥好,思路倒是挺正确的,但是实现上有点小问题,导致最后一刻也没有AC,其实读完题的第一反应是最小生成树,但显然建图是不合适的,因为数据太大了,所以我们需要贪心的去想如何连接比较合适,因为lowbit函数的存在,加上异或,我们只需要考虑每个节点的最小的那个位置的 1 就好了,其实读完题后显然相同权值的结点可以直接连接,代价为0,所以我们在输入的时候就可以顺便去重,对于剩下的结点,其代价肯定是两两互不相同的,我们只需要找到一个位置,在二进制上,对于每个点在这个位置上的表达既有 1 ,又有 0,并且这个二进制的位置最小,找到这样一个位置后,我们只需要让所有这个位置为 1 的结点去与为 0 的结点建边,反过来也是一样,这样就是最优解了,答案为此时结点的个数减一乘以这个二进制

代码:

#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
 
typedef long long LL;

typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;
 
const int N=2e5+100;

unordered_map<int,bool>vis;

int n;

vector<int>a;

bool check(int base)
{
	bool _1=false,_0=false;
	for(int i=0;i<a.size();i++)
	{
		if(a[i]&base)
			_1=true;
		else
			_0=true;
	}
	return _1&&_0;
}

int main()
{
//#ifndef ONLINE_JUDGE
//	freopen("input.txt","r",stdin);
//#endif
//	ios::sync_with_stdio(false);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int num;
		scanf("%d",&num);
		if(vis[num])
			continue;
		vis[num]=true;
		a.push_back(num);
	}
	if(a.size()==1)//如果所有数都相同
		return 0*printf("0\n");
	int base=1;
	while(!check(base))
		base<<=1;
	printf("%lld\n",1LL*(a.size()-1)*base);

	
	
	
	
	
	
	
	
	
	
	return 0;
}
发布了646 篇原创文章 · 获赞 20 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104204310