题解:P11486 「Cfz Round 5」Mata rainen
思路:
首先要判断是否可以建符合题目要求的树,显然,当图中存在环时,不能成为树,因此我们想到使用并查集维护,当输入的两个点的祖先相同时,因为这两个点还会连接,所以一定会成环,此时就结束掉程序;否则就可以建树。
因为这个题目中每条边都只被给出点的最短路径经过了一遍,因此,我们先将输入的点对直接建边(如下图蓝点),然后把剩下的点(下图红点)放在一边,再取出一对输入的点对(绿色点):
然后将绿色点作为头和尾将剩余点或树根串联起来,如图:
这样保证了每条边都可以走到,更重要的是,它代码好写。
写代码时要注意的是:每次连边后都要记录上一次连边的点,下一次要用。
code
#include<bits/stdc++.h>
using namespace std;
#define N 300005
int n,m,f[N];
int find(int x){
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
int last,cnt=0;
struct node{
int x,y;
}e[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
cin>>e[i].x>>e[i].y;
if(find(e[i].x)!=find(e[i].y))f[find(e[i].y)]=find(e[i].x);
else{
cout<<"No"<<'\n';
return 0;
}
}
cout<<"Yes"<<'\n';
for(int i=1;i<m;i++)cout<<e[i].x<<" "<<e[i].y<<'\n';
last=e[m].x;
for(int i=1;i<=n;i++){
if(find(i)==i&&find(i)!=find(e[m].x)){
cout<<last<<" "<<i<<'\n';
last=i;
}
}
cout<<e[m].y<<" "<<last<<'\n';
return 0;
}