题解 P1656 炸铁路
枚举割掉一条边,然后用并查集看是否为会有两个(或者多个)不联通点。
#include <bits/stdc++.h>
using namespace std;
#define N 5010
#define ll long long
template <class T>
inline void read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
a = x * s;
return ;
}
int n, m;
struct edge{
int u, v, next;
} t[N << 1];
int head[N / 10];
int bian = 0;
inline void addedge(int u, int v){
t[++bian] = (edge){u, v, head[u]}, head[u] = bian;
t[++bian] = (edge){v, u, head[v]}, head[v] = bian;
return ;
}
vector < pair<int, int> > ans;
vector < pair<int, int> > G;
int su, sv;
bool vis[N / 10];
int fa[N];
int find_fa(int x){
return x == fa[x] ? x : fa[x] = find_fa(fa[x]);
}
inline void merge(int u, int v){
int fau = find_fa(u), fav = find_fa(v);
if(fau != fav) fa[fau] = fav;
return ;
}
inline void clean(){
memset(fa, 0, sizeof(fa));
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) fa[i] = i;
return ;
}
void dfs(int now){
if(vis[now]) return ;
vis[now] = 1;
for(int i = head[now]; i; i = t[i].next){
int v = t[i].v;
if((su == now && sv == v) || (su == v && sv == now)) continue ;
merge(now, v);
dfs(v);
}
return ;
}
int main(){
read(n), read(m);
for(int i = 1; i <= m; i++){
int x, y;
read(x), read(y);
addedge(x, y);
G.push_back(make_pair(x, y));
}
for(int i = 0; i < G.size(); i++){
clean();
su = G[i].first;
sv = G[i].second;
bool flag = 0;
for(int j = 1; j <= n; j++)
if(!vis[j]) dfs(j);
for(int j = 1; j <= n; j++)
for(int h = j + 1; h <= n; h++){
int fau = find_fa(j), fav = find_fa(h);
if(fau != fav){
flag = 1;
break;
}
}
if(flag) ans.push_back(make_pair(min(su, sv), max(su, sv)));
}
sort(ans.begin(), ans.end());
for(int i = 0; i < ans.size(); i++){
printf("%d %d\n", ans[i].first, ans[i].second);
}
return 0;
}