CF1817B 题解

· · 题解

题目分析

发现题意就是说让你找一个环,满足环上存在一个点 $u$,向环外连了至少两条边。于是贪心地考虑,我们只需要试图让这个点向环内的连边尽量少。容易发现至少要有两条,而只要找出一个极小环就能取到两条,于是边双缩点之后判断是否有在环上且度数 $\geq 4$ 的点即可,从该点开始找一个极小环再任意找两条边便满足题目要求。 ## 代码 赛时代码很丑。 ```cpp /* author: PEKKA_l Sexy_goodier _ xiaoqing */ #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define int long long int t,n,m,u,v,dfn[2005],low[2005],vis[2005],stk[2005],cntd,top,flag[2005],cnts,sz[2005]; vector <int> e[2005]; void dfs(int x,int fat) { dfn[x]=low[x]=++cntd; stk[++top]=x; vis[x]=1; for(auto i:e[x]) { if(i==fat) continue; if(!dfn[i]) {dfs(i,x); low[x]=min(low[x],low[i]);} else if(vis[i]) {low[x]=min(low[x],dfn[i]);} } if(dfn[x]==low[x]) { cnts++; while(1) { int nw=stk[top--]; flag[nw]=cnts; sz[cnts]++; vis[nw]=0; if(nw==x) break; } } } void tarjan() { for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,i); } int zt[2005],hn[2005],cnth,us[2005],ss[2005]; bool dfs2(int x,int bf,int to) { if(x==to&&zt[x]==1) return 1; if(zt[x]) return 0; zt[x]=1; for(auto i:e[x]) { if(i==bf) continue; if(dfs2(i,x,to)) { hn[++cnth]=i; return 1; } } return 0; } void solve(int x) { for(int i=1;i<=n;i++) zt[i]=hn[i]=us[i]=ss[i]=0; cnth=0; dfs2(x,x,x); for(auto i:e[x]) ss[i]=1; int num=0; for(int i=3;i<=cnth;i++) { if(ss[hn[i]]) {num=i; break;} } for(int i=2;i<=num;i++) us[hn[i]]=1; cout<<num+2<<endl; hn[num+1]=x; for(int i=2;i<=num+1;i++) cout<<hn[i-1]<<" "<<hn[i]<<endl; int cntt=0; for(auto i:e[x]) { if(!us[i]) {cntt++; cout<<x<<" "<<i<<endl;} if(cntt==2) break; } } signed main() { cin>>t; while(t--) { cin>>n>>m; for(int i=1;i<=n;i++) e[i].clear(); cntd=cnts=top=0; for(int i=1;i<=n;i++) dfn[i]=low[i]=vis[i]=stk[i]=flag[i]=sz[i]=0; for(int i=1;i<=m;i++) {cin>>u>>v; e[u].pb(v); e[v].pb(u);} tarjan(); bool ok=0; for(int i=1;i<=n;i++) { if(e[i].size()>=4&&sz[flag[i]]>=3) { cout<<"YES"<<endl; ok=1; solve(i); break; } } if(!ok) cout<<"NO"<<endl; } } ```