无向图的割点和桥
割点:
void tarjan(int u){ dfn[u]=low[u]=++cnt; int flag=0; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){//就一个割点判断法则没必要解释什么了吧? flag++; if(u!=rt||flag>1)cut[u]=1; } }else low[u]=min(low[u],dfn[v]); } }
桥:
void tarjan(int u,int in_edge){//in_edge表示递归进入每个节点的边的编号 dfn[u]=low[u]=++cnt; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!dfn[v]){ tarjan(v,i); low[u]=min(low[u],low[v]);//在搜索树上的边 if(low[y]>dfn[u])//桥判定法则 bridge[i]=bridge[i^1]=1;//这条边和它的反向边都是桥 }else if(i!=(in_edge^1))///实际上也就是不要走到父亲去 low[u]=min(low[u],dfn[v]);//不在搜索树上的边 } } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); addedge(x,y);addedge(y,x); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,0); for(int i=0;i<tot;i+=2) if(bridge[i]) printf("%d %d\n",e[i^1].v,e[i].v);//输出桥两边的点 //printf("%d %d\n",to(i^1),to(i));//输出桥两边的点 }
poj 1144
http://poj.org/problem?id=1144
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> using namespace std; typedef long long ll; int mi(int x,int y){ return x<y?x:y; } inline int read(){ int sum=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=0; ch=getchar(); } while(ch>='0'&&ch<='9'){ sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar(); } //cout<<"~~"<<endl; return x?sum:-sum; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int M=101; int dfn[M],low[M],head[M],cut[M],tot,cnt,son; struct node{ int v,nextt; }e[M*M]; void addedge(int u,int v){ e[tot].v=v; e[tot].nextt=head[u]; head[u]=tot++; } void tarjan(int u){ dfn[u]=low[u]=++cnt; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!dfn[v]){ tarjan(v); if(u==1) son++; else{ low[u]=mi(low[u],low[v]); if(dfn[u]<=low[v]) cut[u]=1; } } else low[u]=mi(low[u],dfn[v]); } } int n; void init(){ for(int i=0;i<=n;i++) dfn[i]=low[i]=cut[i]=0,head[i]=-1; son=0,tot=0,cnt=0; } int main(){ while(~scanf("%d",&n)&&n){ init(); int u; while(scanf("%d",&u)&&u){ while(getchar()!='\n'){ int v; scanf("%d",&v); addedge(u,v); addedge(v,u); } } tarjan(1); int ans; if(son>=2) ans=1; else ans=0; for(int i=1;i<=n;i++) if(cut[i]) ans++; //cout<<ans<<endl; write(ans); putchar('\n'); } return 0; }
题:http://poj.org/problem?id=1523
题意:问割点包含的点的个数
#include<bits/stdc++.h> using namespace std; const int M=1e3+3; int head[M],dfn[M],cut[M],low[M],n,tot,cnt,rt; struct node{ int v,nextt; }e[M*10]; void addedge(int u,int v){ e[tot].v=v; e[tot].nextt=head[u]; head[u]=tot++; } void tarjan(int u){//cout<<"!!"<<endl; dfn[u]=low[u]=++cnt; int flag=0; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){ flag++; if(u!=rt||flag>1) cut[u]++; } } else low[u]=min(low[u],dfn[v]); } } void init(){ memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(cut,0,sizeof(cut)); n=0,tot=0,cnt=0; } int main(){ int u,v,sign=1; while(~scanf("%d",&u)&&u){ init(); n=max(n,u); while(scanf("%d",&v)){ n=max(n,v); addedge(u,v); addedge(v,u); scanf("%d",&u); n=max(n,u); if(!u) break; } for(int i=1;i<=n;i++) if(!dfn[i]) rt=i,tarjan(i); printf("Network #%d\n",sign++); int flag=0; for(int i=1;i<=n;i++){ if(cut[i]){ flag=1; printf(" SPF node %d leaves %d subnets\n",i,1+cut[i]); } } if(!flag) printf(" No SPF nodes\n"); putchar('\n'); } return 0; }