poj 3352 3177 桥 缩点
题意:求至少添加几条边,使原图中没有桥。
分析:找出边连通分量,缩点,形成一棵树,树叶有cnt个,则结果为(cnt+1)/2
#define M 1011 struct Node{ int v,next; }edge[M<<4]; int len; int old[M],n; int nb; int tim[M],t; int sta[M],top; int low[M],hash[M];//原结点向新结点映射 int rudu[M]; int bs[M],be[M],bb;//桥 void add(int &kind,int v){ edge[len].next=kind; edge[len].v=v; kind=len++; } void dfs(int u, int father) { tim[u] = low[u] = t ++; sta[++top] = u; for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(v == father) continue; if(tim[v] == -1) {//父子边 dfs(v, u); checkmin(low[u],low[v]); if(tim[u] < low[v]){ //i是桥 bs[bb]=u; be[bb++]=v; } } else checkmin(low[u],tim[v]);//返祖边 } if(tim[u] == low[u]) { //u是连通分量的第一个点 int v=-1; while(u != v){ v = sta[top--]; hash[v]=nb; } nb++; } } int cnt; void Tarjan() { FOR(i,1,n+1) { if(tim[i] == -1) dfs(i , -1); } memset(rudu,0,sizeof(int)*(nb+1)); /*FOR(u,1,n+1) { for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(hash[u] != hash[v]) rudu[ hash[v] ]++; } }*/ FF(i,bb){ int u=bs[i],v=be[i]; rudu[ hash[u] ]++; rudu[ hash[v] ]++; } FF(i,nb) if(rudu[i]==1) cnt++; cout<<(cnt+1)/2<<endl; /* FOR(u,1,n+1) { for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(low[u] != low[v]) rudu[ low[v] ]++; } } */ } void init(){ memset(old,-1,sizeof(int)*(n+1)); memset(tim,-1,sizeof(int)*(n+1)); memset(hash,-1,sizeof(int)*(n+1)); len = t = top = nb = cnt = bb = 0; } void build(){ int r,a,b; cin>>r; FF(i,r){ cin>>a>>b; add(old[a],b); add(old[b],a); } } int main(){ while(cin>>n){ init(); build(); Tarjan(); } }
#define M 1011 struct Node{ int v,next; }edge[M<<4]; int len; int old[M],n; int nb; int tim[M],t; int sta[M],top; int low[M],hash[M];//原结点向新结点映射 int rudu[M]; int bs[M],be[M],bb;//桥 void add(int &kind,int v){ edge[len].next=kind; edge[len].v=v; kind=len++; } void dfs(int u, int father) { tim[u] = low[u] = t ++; sta[++top] = u; for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(v == father) continue; if(tim[v] == -1) {//父子边 dfs(v, u); checkmin(low[u],low[v]); if(tim[u] < low[v]){ //i是桥 bs[bb]=u; be[bb++]=v; } } else checkmin(low[u],tim[v]);//返祖边 } if(tim[u] == low[u]) { //u是连通分量的第一个点 int v=-1; while(u != v){ v = sta[top--]; hash[v]=nb; } nb++; } } int cnt; void Tarjan() { FOR(i,1,n+1) { if(tim[i] == -1) dfs(i , -1); } memset(rudu,0,sizeof(int)*(nb+1)); /*FOR(u,1,n+1) { for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(hash[u] != hash[v]) rudu[ hash[v] ]++; } }*/ FF(i,bb){ int u=bs[i],v=be[i]; rudu[ hash[u] ]++; rudu[ hash[v] ]++; } FF(i,nb) if(rudu[i]==1) cnt++; cout<<(cnt+1)/2<<endl; /* FOR(u,1,n+1) { for(int i = old[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(low[u] != low[v]) rudu[ low[v] ]++; } } */ } void init(){ memset(old,-1,sizeof(int)*(n+1)); memset(tim,-1,sizeof(int)*(n+1)); memset(hash,-1,sizeof(int)*(n+1)); len = t = top = nb = cnt = bb = 0; } void build(){ int r,a,b; cin>>r; FF(i,r){ cin>>a>>b; add(old[a],b); add(old[b],a); } } int main(){ while(cin>>n){ init(); build(); Tarjan(); } }