Codeforces Round #599 (Div. 2) D

题目链接:http://codeforces.com/contest/1243/problem/D

翻译:给n个点m条边(1<=n<=1e5,0<=m<=min(n*(n-1)/2,1e5)),构成一张无向图,给的m条边上,边权均为1,在原有m条边的基础上再添加边权为0的边把图变成完全图,这时候问,构成最小生成树最小路径。

 

思路:就是联通图,有边权为0的两个点可以缩成一个点,生成树答案就是连通图个数减一。那么,连通图怎么找呢,要保证被遍历过的点不能再影响到时间复杂度,这就是这题的关键,那么如何保证被遍历过的点不再能影响时间复杂度呢,这时候,只需要用一个容器把所有未访问的点存起来,再用这些点来进行遍历,每个点能访问到未访问的点先用容器存起来,再把这些点从存未访问点的大容器中删掉,然后再遍历小容器遍历这些点。这样,找联通图的复杂度的规模就被缩小到n了,即1e5。

我的代码使用了map来存边,所以时间复杂度上升到了nlogn不过并不关键,一般来说map是不如unordered_map,但是unordered_map也可以被卡成O(n),那样也可能T,所以使用map能保证红黑树的复杂度是logn,更加稳妥

ac代码:

#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <algorithm>
#define ms(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
using namespace std;
const int maxn =1e5+5;//提交记得修改
set<int>s;//用于存放未访问的边
map<int,bool>mp[maxn];
int n,m;
bool vis[maxn];
void dfs(int u){
	vis[u]=true;
	set<int>::iterator it;
	vector<int>v;
	for(it=s.begin();it!=s.end();it++)if(!mp[u][*it])v.push_back(*it);
    //若是被map存了的边,则不加到容器中
	int sz=v.size();
	for(int i=0;i<sz;i++)s.erase(v[i]);
	for(int i=0;i<sz;i++)dfs(v[i]);
}
int main()
{
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);//提交记得注释
	scanf("%d%d",&n,&m);
	while(m--){
		int u,v;
		scanf("%d%d",&u,&v);
		mp[u][v]=mp[v][u]=true;
	}
	for(int i=1;i<=n;i++)s.insert(i);
	int ans=0;
	for(int i=1;i<=n;i++)if(!vis[i])ans++,dfs(i);
	printf("%d\n",ans-1);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值