Dream_poetry
2024-11-15 20:27:48
首先,由于我们只需要保证编号小于等于
所以,必然有一组最优解保留了所有大于
然后将这些边所连的点通过并查集归在一起,方便后续判环。
然后枚举每一条边,如果这条边所连的两个点有一个的编号小于等于
如果保留这条边会产生环,那我们必然舍弃,计入答案即可。
那如果保留这条边不会产生环,我们是否要保留呢?
其实此时问题可以转化为
那么显然我们肯定是要能连尽量连,这样才能保证删除的边最少。
当上述情况发生时,其实就相当于一个独立点和一个连通块第一次尝试连边,那么由于我们无法保证后续是否会出现新的边来把这两部分连起来,为保证最优性,我们肯定是要保留这条边的。
至此,思路显然了,代码也就简单了,利用并查集判环即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int k;
struct node{
int x,y;
};
node e[2000005];
node ans[2000005];
int fa[1000005];
int cnt;
inline int find(int x){
if (fa[x]!=x){
fa[x]=find(fa[x]);
}
return fa[x];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for (int i=1;i<=n;i++){
fa[i]=i;
}
cin>>k;
for (int i=1;i<=m;i++){
cin>>e[i].x>>e[i].y;
if (e[i].x>k && e[i].y>k){
fa[find(e[i].x)]=find(e[i].y);
}
}
for (int i=1;i<=m;i++){
int u=find(e[i].x);
int v=find(e[i].y);
if (e[i].x<=k || e[i].y<=k){
if (u==v){
cnt++;
ans[cnt]=e[i];
}
else{
fa[u]=v;
}
}
}
cout<<cnt<<"\n";
for (int i=1;i<=cnt;i++){
if (ans[i].x<ans[i].y){
cout<<ans[i].x<<' '<<ans[i].y<<"\n";
}
else{
cout<<ans[i].y<<' '<<ans[i].x<<"\n";
}
}
return 0;
}