题解:P2247 SAC#1 - ACOJ云评测计划

· · 题解

很简单的一道题

题意

在一个 n 个点的图中找出 k 个点,使得删去这 k 个点后图不连通。

思路

我们注意到数据范围范围 k \le 3 和 n \le 500 数据很小,直接暴力就能过。

具体地:

$ k=2 $ 时,枚举删去 $ 1 $ 个点,在删去这个点后的图上求出割点,这 $ 2 $ 个点就是原图的割点集。 $ k=3 $ 时,同理枚举删去 $ 2 $ 个点后再求割点,这 $ 3 $ 个点就是原图的割点集。 **注意**:题目给的可能不是连通图,需要特判! ::::success[AC Code] ```cpp #include <bits/stdc++.h> using namespace std; #define ll int #define N 505 ll n,m,k; struct node{ ll nx,to; }; vector<node>e; ll h[N*2]; void add(ll a,ll b){ e.push_back({h[a],b}); h[a]=e.size()-1; e.push_back({h[b],a}); h[b]=e.size()-1; } ll root=1,tot,low[N],dfn[N],num; bool cut[N],vis[N]; void tar(ll u,ll fa){ ll cnt=0; low[u]=dfn[u]=++tot; for(ll i=h[u];~i;i=e[i].nx){ ll v=e[i].to; if(vis[v]) continue; if(!dfn[v]){ cnt++; tar(v,u); low[u]=min(low[u],low[v]); if((u==root&&cnt>=2)||(u!=root&&low[v]>=dfn[u])){ num++; cut[u]=1; } } else if(v!=fa) low[u]=min(low[u],dfn[v]); } } void clear(){ root=1; tot=0; memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); memset(cut,0,sizeof cut); } ll Root(ll a,ll b){ if(a==1||b==1){ for(ll i=2;i<=n;i++) if(i!=a&&i!=b) return i; } else return 1; } int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); memset(h,-1,sizeof h); cin>>n>>m>>k; for(ll i=1;i<=m;i++){ ll u,v; cin>>u>>v; add(u,v); } tar(1,-1); for(ll i=1;i<=n;i++){ if(!dfn[i]){ cout<<"Poor SOL!"; return 0; } } if(k==1){ for(ll i=1;i<=n;i++) if(cut[i]){ cout<<i; return 0; } cout<<"How oversuspicious you are, SOL!"; } if(k==2){ for(ll x=1;x<=n;x++){ clear(); vis[x]=1; if(x==1){ root=2; tar(2,-1); } else tar(1,-1); vis[x]=0; for(ll y=1;y<=n;y++){ if(y==x) continue; if(cut[y]){ cout<<x<<' '<<y; return 0; } } } cout<<"How oversuspicious you are, SOL!"; } if(k==3){ for(ll x=1;x<=n;x++){ for(ll y=1;y<=n;y++){ if(x==y) continue; clear(); root=Root(x,y); vis[x]=vis[y]=1; tar(root,-1); vis[x]=vis[y]=0; for(ll z=1;z<=n;z++){ if(z==x||z==y) continue; if(cut[z]){ cout<<x<<' '<<y<<' '<<z; return 0; } } } } cout<<"How oversuspicious you are, SOL!"; } return 0; } ``` ::::