原题: http://codeforces.com/problemset/problem/1133/F2
题意: 给出一棵树,没有自环重边,从这棵树中扒出一棵树,节点1有d个连点。
解析:
分析将节点1和与之相连的边去掉后的图。
首先分析节点1的两个有连边的点p1、p2,如果p1和p2之间有一条不通过点1的路径。假设p1可以跑到p2,那么p2一定可以跑到p1,且p1可以跑到的其他点,p2都可以跑到。这个结论很重要。
将这些可以互相连通的点放入一个集合。设集合的数量为k。
- 如果k=d,那么刚刚好,直接跑每个集合即可;
- 如果k>d,说明点1不可能用d条边将所有点都连起来,输出NO;
- 如果k<d,那么说明我需要将某些集合拆成多个集合,来凑这个d;比方说点1连了p1和p2,而p1和p2属于一个集合。如果此时d=2,那么我就把p1和p2拆开。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define repp(i,a,b) for(register int i=a;i>=b;i--)
#define mmm(p) memset(p,0,sizeof p)
#define pill pair<int,int>
#define debug(i) printf("#%d\n",i)
#define F double
typedef long long LL;
LL read() {
LL ans=0;
char last=' ',ch=getchar();
while(ch<'0' || ch>'9')
last=ch,ch=getchar();
while(ch>='0' && ch<='9')
ans=ans*10+ch-'0',ch=getchar();
if(last=='-')
ans=-ans;
return ans;
}
const int maxn=2e5+5,maxm=4e5+5;
int head[maxn],to[maxm],nex[maxm],now;
void add(int a,int b){
nex[++now]=head[a];head[a]=now;to[now]=b;
}
unordered_set<int>Set[maxn]; // 联通的点集
bool vis[maxn];
vector<int>set_id; // 集合标号
bool link_one[maxn]; // 与1相连
void dfs(int p,int id){
if(link_one[p])Set[id].insert(p);
vis[p]=1;
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(vis[u])continue;
dfs(u,id);
}
}
void prin(int p,int fa){ //k=d的情况
vis[p]=1;
printf("%d %d\n",p,fa);
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(vis[u])continue;
prin(u,p);
}
}
void bfs(int id,int ct){ //k<d的情况
ct++;
queue<int>Q;
unordered_set<int>::iterator it=Set[id].begin();
while(ct--){
int p=(*it);++it;
vis[p]=1;
Q.push(p);
printf("%d %d\n",1,p);
}
while(!Q.empty()){
int p=Q.front();Q.pop();
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(vis[u])continue;
vis[u]=1;Q.push(u);
printf("%d %d\n",p,u);
}
}
}
int main(){
int n=read(),m=read(),d=read();
rep(i,1,m){
int a=read(),b=read();
add(a,b);
add(b,a);
}
int ct=0;
for(int i=head[1];i;i=nex[i]){
link_one[to[i]]=1;
ct++;
}
if(ct<d)return 0*printf("NO\n");
vis[1]=1;
int set_num=0;
for(int i=head[1];i;i=nex[i]){
int u=to[i];
if(vis[u])continue;
set_num++;
set_id.push_back(u);
dfs(u,u);
}
if(set_num>d)return 0*printf("NO\n");
printf("YES\n");
if(set_num==d){
memset(vis,0,sizeof(vis));
vis[1]=1;
for(int i=0;i<set_id.size();i++){
prin(set_id[i],1);
}return 0;
}
int need=d-set_num;
int now=0;
memset(vis,0,sizeof(vis));
vis[1]=1;
while(need>0){
int id=set_id[now++];
int siz=Set[id].size();
bfs(id,min(siz-1,need));
need-=min(siz-1,need);
}
while(now<set_id.size()){
bfs(set_id[now++],0);
}
}