题目链接:点击打开链接
题意:给出无向图n个点,m条边 (2 ≤ n ≤ 200 000, 1 ≤ m ≤ min(400 000, n·(n - 1) / 2))
找出一个生成树,使得s点的度不超过ds,t点的度不超过dt;
解:
数据分别是20w和40w,又是找生成树,显然是kurskal。
首先,我们先不管s和t点,把其他点弄成生成树再说。
然后,我们再考虑s点和t点与其他点的连边。
最后,再考虑s和t之间的连边(贪心的策略)
要注意的问题是:在考虑s点和t点与其他点的连边是要判断是否s、t的度超过了ds、dt。因为,s可以连的点,t也可能连,那么谁去连呢?那就要看谁的度不超。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
struct edge
{
int en,next;
edge(int en=0,int next=-1):
en(en),next(next){}
};
struct edge E[MAXN*4],e[MAXN*4];
int p[MAXN],num,fa[MAXN];
inline void add(int st,int en)
{
E[num]=edge(en,p[st]);
p[st]=num++;
}
int findfa(int x)
{
if(x==fa[x])return x;
return fa[x]=findfa(fa[x]);
}
int main()
{
int n,m,s,t,ds,dt,i,dus,dut;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(p,-1,sizeof(p));
num=0;
for(i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
e[i]=edge(u,v);
}
scanf("%d%d%d%d",&s,&t,&ds,&dt);
for(i=1;i<=n;i++)fa[i]=i;
vector<edge>ans;
for(i=1;i<=m;i++)
{
int tx=e[i].en;
int ty=e[i].next;
if(tx==s||tx==t||ty==s||ty==t)continue;
tx=findfa(tx);ty=findfa(ty);
if(tx!=ty)
{
fa[tx]=ty;
ans.push_back(e[i]);
}
}
dus=0,dut=0;
for(i=p[s];i!=-1;i=E[i].next)
{
int en=E[i].en;
if(en==t)continue;
int tx=findfa(s);
int ty=findfa(en);
if(tx!=ty&&dus<ds)
{
dus++;
fa[tx]=ty;
ans.push_back(edge(s,en));
}
}
for(i=p[t];i!=-1;i=E[i].next)
{
int en=E[i].en;
if(en==s)continue;
int tx=findfa(t);
int ty=findfa(en);
if(tx!=ty&&dut<dt)
{
dut++;
fa[tx]=ty;
ans.push_back(edge(t,en));
}
}
for(i=p[s];i+1;i=E[i].next)
{
int en=E[i].en;
if(en!=t)continue;
int tx=findfa(s);
int ty=findfa(t);
if(tx!=ty)
{
fa[tx]=ty;
dus++;
dut++;
ans.push_back(edge(s,t));
break;
}
}
if(dus>ds||dut>dt)
{
puts("No");
continue;
}
int tx=findfa(s);
bool yes=0;
for(i=1;i<=n;i++)
{
int ty=findfa(i);
if(tx!=ty)
{
yes=1;break;
}
}
if(yes)
{
puts("No");
continue;
}
puts("Yes");
for(i=0;i<n-1;i++)
{
printf("%d %d\n",ans[i].en,ans[i].next);
}
}
return 0;
}