题目链接:https://codeforces.com/problemset/problem/723/F
题解:
首先先删去 s 和 t,原图一定是若干个连通块,先把这些块的生成森林求出来,之后将连通块缩点
然后考虑如何与 s/t 连边?首先对于每个缩完的点(下称点)来说,一定是至少和 s/t 其中一个点连边(原图连通)。如果只与 s/t 中的 1 个相连,那就直接连就行了,否则,先贪心的连 ds/dt 剩余量多的对应的 s/t,注意这样操作完之后变成了2个连通块,而且 s/t 分属于两个块中。最后就连那一条边即可,要么是s-t直接连(如果有边),要么就是某个点既连 s 又连 t
细节很多,代码不好写
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <set>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 4e5 + 5;
int n,m;
vector<int>g[maxn];
set<int>h[maxn], poi[maxn];
int x[maxn], y[maxn];
int s,t,ds,dt,vis[maxn],cnt2;
vector<pii>init_st;
int con[maxn][2], v[maxn];
// con[][0/1] 缩点之后与 s/t 连通 v[] 缩点之后第一轮是和 s/t 连边(防止连重了)
void dfs(int x,int id){
vis[x] = id;
for(int u : g[x])if(!vis[u]){
init_st.push_back(mpr(x,u)); // 每个连通块的生成森林一定在答案中
dfs(u, id);
}
}
signed main(){
// freopen("CF723F.in","r",stdin);
// freopen("CF723F.out","w",stdout);
int fg = 0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x[i],&y[i]);
}
scanf("%d%d%d%d",&s,&t,&ds,&dt);
if(s > t)swap(s, t), swap(ds, dt);
for(int i=1;i<=m;i++){
if(s == x[i] || s == y[i] || t == x[i] || t == y[i]){
}else g[x[i]].push_back(y[i]), g[y[i]].push_back(x[i]);
// 建图 删去 和 s/t 相连的边
}
int cnt = 0;
for(int i=1;i<=n;i++)
if(i!=s && i!=t && !vis[i]){
dfs(i, ++cnt);
}
// x -> vis[x] 缩点
for(int i=1;i<=m;i++){
if((x[i]==s&&y[i]==t) || (x[i]==t&&y[i]==s)){fg = 1;continue;}
if(s == x[i] || s == y[i] || t == x[i] || t == y[i]){
int fx = x[i], fy = y[i];
if(s == x[i] || t == x[i])swap(fx, fy);
// fx -> s/t
poi[vis[fx]].insert(fy);
con[vis[fx]][fy == s ? 0 : 1] = fx;
}
}
// 缩点之后每个点先和 s/t 连一条边,连完之后图一定是 2 个连通块
// 先连只与s/t一个相连的,再连两个都相连的(只需要连一条)
for(int i=1;i<=cnt;i++){
if(poi[i].size() == 1){
int to = *poi[i].begin();
if(to == s){
-- ds;
init_st.push_back(mpr(con[i][0], s));
}
else{
--dt;
init_st.push_back(mpr(con[i][1], t));
}
}
}
int gg = 0;
for(int i=1;i<=cnt;i++)
if(poi[i].size() == 2){
if(ds > 0){
v[i] = 1;
-- ds;
init_st.push_back(mpr(con[i][0], s));
}else if(dt > 0){
v[i] = 2;
-- dt;
init_st.push_back(mpr(con[i][1], t));
}else gg = 1;
}
// 最后再连1条,使得图连通(某个点与s/t均连 或者 s-t 直接连)
int ok = 0;
if(ds+dt > 0){
if(ds > 0 && dt > 0 && fg)init_st.push_back(mpr(s, t)), ok = 1;
else
for(int i=1;i<=cnt;i++){
if(poi[i].size() == 2){
if(ds > 0 && v[i] != 1){
ok=1;
-- ds;
init_st.push_back(mpr(con[i][0], s));
}else if(dt > 0 && v[i] != 2){
ok=1;
-- dt;
init_st.push_back(mpr(con[i][1], t));
}
break;
}
}
}
if(!ok || gg)puts("No");
else{
puts("Yes");
for(pii u : init_st)printf("%d %d\n",u.first,u.second);
}
return 0;
}
标签:int,Tree,st,init,maxn,CF723F,dt,include
From: https://www.cnblogs.com/SkyRainWind/p/16967394.html