题意:给出一个图,构造一个点1的度为d的生成树
一开始就先判断下点1的度是否大于等于d,不够的话肯定是构造不了的。
先不管点1,先对剩下的点根据连通性分下块。这时候这些块都至少与点1有一条边,一个块里可能有几个点与点1有边,随便先连一个就可以了。这时候如果有一个块没有一个点与点1有边,或者连的边数已经大于d,也是构造不了了。如果边数还不够d,那么就再选一些没跟点1连过的点且与点1有边的点跟点1相连,直到够d了为止,最后按照普通的生成树做法,注意这时不能再加入新的有端点是1的边了。
根据连通性分成块的好处是在块中随便选点与点1相连,还可以保证最后可能有边使得块内剩下的与整个图连通。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,d;
const int N=2e5+5;
int head[N],cnt;
struct node{
int u,v,nxt;
}edge[N<<1];
vector<int>kuai[N],cd;
vector<pair<int,int> >ans;
int top;
int vis[N];
bool conn[N];
int fa[N];
int findfa(int x){
return fa[x]=fa[x]==x?x:findfa(fa[x]);
}
void addedge(int u,int v){
edge[++cnt].v=v;
edge[cnt].u=u;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(int u){//根据连通性分块
vis[u]=top;
kuai[top].push_back(u);
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(v==1||vis[v])continue;
dfs(v);
}
}
int main(){
scanf("%d%d%d",&n,&m,&d);
memset(head,-1,sizeof(head));
int tp=0;//一开始记录点1的度
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
if(v==1||u==1)tp++;
}
if(tp<d){
printf("NO\n");
return 0;
}
for(int i=2;i<=n;i++){
if(!vis[i]){
top++;
dfs(i);
}
}
for(int i=head[1];~i;i=edge[i].nxt){//找一下与点1有边的点
int v=edge[i].v;
conn[v]=true;
cd.push_back(v);
}
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=top;i++){//每个块找个点与点1相连
bool ff=false;
for(int j=0;j<kuai[i].size();j++){
if(conn[kuai[i][j]]){
ff=true;
fa[kuai[i][j]]=1;
ans.push_back(make_pair(1,kuai[i][j]));
break;
}
}
if(!ff){
printf("NO\n");
return 0;
}
}
if(ans.size()>d){
printf("NO\n");
return 0;
}
d-=ans.size();
for(int i=0;i<cd.size()&&d;i++){//补一下不够的边数
int v=cd[i];
if(fa[v]==1)continue;
fa[v]=1;
d--;
ans.push_back(make_pair(1,v));
}
if(d!=0){
printf("NO\n");
return 0;
}
for(int i=1;i<=cnt;i++){
int fa1=findfa(edge[i].u),fa2=findfa(edge[i].v);
if(edge[i].u==1||edge[i].v==1)continue;
if(fa1!=fa2){
fa[fa1]=fa2;
ans.push_back(make_pair(edge[i].u,edge[i].v));
}
}
printf("YES\n");
for(int i=0;i<ans.size();i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
return 0;
}