前言
这道题怎么可以没you题解呢
思路分析
即使每个人都有朋友,但是一定会有一个人的前面没有站着朋友,那么我们就把这些朋友放在一个连通块里,
那么如果里面有一个点(i==f[i])说明他必须要站在最前面,,题目要求字典序最小,那么我么就尽量把编号较
大的点合并到最小的点里,然后把每队朋友关系连边,把能到达的点存入一个优先队列里(小根堆),这样每次
记录答案是得到的就是最小的
代码
//#pragma GCC optimize(3,"inline","Ofast","fast-math","no-stack-protector","unroll-loops")
//#pragma GCC target("sse","sse2","sse3","sse4","avx","avx2","popcnt")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define RG register
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e6+10;
int n,m,tot,cnt;
int f[N],ans[N];
int h[N],nex[N<<1],ver[N<<1],vis[N];
priority_queue<int>q;
inline int find(int x)
{
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
inline void add(int x,int y)
{
nex[tot]=h[x];
ver[tot]=y;
h[x]=tot++;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);tot=0;
memset(h,-1,sizeof(h));cnt=0;
memset(vis,0,sizeof(vis));
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
int xx=find(x),yy=find(y);
if(xx==yy) continue;
if(xx<yy) swap(xx,yy);
//大的往小的合并
f[xx]=yy;
}
int tot=0;
for (int i=1;i<=n;i++)
if(f[i]==i) q.push(-i),vis[i]=1,tot++;
//取负是为了满足大根堆性质
printf("%d\n",tot);
while(!q.empty())
{
int k=-q.top();q.pop();
ans[++cnt]=k;
for (int i=h[k];~i;i=nex[i])
{
int j=ver[i];
if(vis[j]) continue;
vis[j]=1;
q.push(-j);
}
}
for (int i=1;i<=cnt;i++) printf("%d ",ans[i]);
puts("");
}
return 0;
}
京公网安备 11010502036488号