点这里 |
---|
题意: 给定一个无向图,要求输出图中多余边和冲突边的数量。
题解: 多余边就是割边,求割边套模板就能做。冲突边:一个点双连通分量中如果边数大于点数,则所有边都是冲突边。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n, m, u, v;
int ans1, ans2, ds_cnt, dfn;
int low[N], num[N], vis[N];
vector<int> G[N], ds[N];
stack<int> st;
void init(){
ans1 = ans2 = ds_cnt = dfn = 0;
for(int i = 0; i <= n; i++) num[i] = low[i] = 0, G[i].clear(), ds[i].clear();
}
void dfs(int u, int fa){
num[u] = low[u] = ++dfn;
st.push(u);
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(v == fa) continue;
if(!num[v]){
dfs(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= num[u]){ //gedian
if(low[v] > num[u]) ans1++; //gebian
ds_cnt++;
while(1){
int now = st.top();
st.pop();
ds[ds_cnt].push_back(now);
if(now == v) break;
}
ds[ds_cnt].push_back(u);
}
}else
low[u] = min(low[u], num[v]);
}
}
void solve(){
for(int i = 1; i <= ds_cnt; i++){
int cnt = 0;
for(int u = 0; u < ds[i].size(); u++) vis[ds[i][u]] = 1;
for(int u = 0; u < ds[i].size(); u++)
for(int v = 0; v < G[ds[i][u]].size(); v++)
if(vis[G[ds[i][u]][v]]) cnt++;
for(int u = 0; u < ds[i].size(); u++) vis[ds[i][u]] = 0;
for(int j = 0; j < ds[i].size(); j++){ int u = ds[i][j]; vis[u] = 0;}
if(cnt / 2 > ds[i].size()) ans2 += cnt / 2;
}
}
int main(){
while(~scanf("%d%d", &n, &m) && (n + m)){
init();
while(m--){
scanf("%d%d", &u, &v);
G[u].push_back(v), G[v].push_back(u);
}
for(int i = 0; i < n; i++) if(!num[i]) dfs(i, -1);
solve();
printf("%d %d\n", ans1, ans2);
}
return 0;
}