点双联通分量:没有割点;
边双联通分量:没有割边;
如何求无向图割点?
dfs建树解决;
low数组表示可到达祖先,num表示递归深度;
如果 low[v]>=num[u],说明是割点;
如果 low[v]>=num[u] 说明是割边;
如果 num[v]<num[u]&&v!=fa,说明是回退边,
Network
POJ - 1144给你一个无向图,求割点;
#include<iostream> #include<vector> #include<cstdio> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define pf push_front #define fi first #define se second 11 typedef long long ll; typedef unsigned long long ull; typedef long double ldb; typedef double db; const ll INF=0x3f3f3f3f3f3f3f3fLL; const int inf=0x3f3f3f3f;//0x7fffffff; const double eps=1e-9; const ll MOD=9999991; const int maxn=1e2+5; int n; vector<int>e[maxn]; bool iscut[maxn]; int low[maxn],dep[maxn],dfn; void dfs(int u,int fa){ low[u]=dep[u]=++dfn; int child=0; for(int i=0;i<e[u].size();i++){ int v=e[u][i]; if(!dep[v]){ child++; dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dep[u]&&u!=1)iscut[u]=1; } else if(dep[v]<dep[u]&&v!=fa) low[u]=min(low[u],dep[v]); } if(u==1&&child>=2)iscut[1]=1; } int main(){ while(~scanf("%d",&n),n){ for(int i=1;i<=n;i++)e[i].clear(),iscut[i]=0,low[i]=0,dep[i]=0; int u,v; while(~scanf("%d",&u),u){ while(getchar()!='\n'){ scanf("%d",&v); e[u].pb(v); e[v].pb(u); } } dfn=0; dfs(1,1); int ans=0; for(int i=1;i<=n;i++)ans+=iscut[i]; // cout<<"ans:"<<ans<<endl; cout<<ans<<endl; } // system("pause"); return 0; }
Road Construction
给你一个无向图:问你最少加几条边,使得图成为双联通分量 ;
low相同的为一个联通块,遍历一遍,然后缩点,
求出答案;
#include<iostream> #include<vector> #include<cstdio> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define pf push_front #define fi first #define se second 11 typedef long long ll; typedef unsigned long long ull; typedef long double ldb; typedef double db; const ll INF=0x3f3f3f3f3f3f3f3fLL; const int inf=0x3f3f3f3f;//0x7fffffff; const double eps=1e-9; const ll MOD=9999991; const int maxn=1e3+5; int dfn,n,m; int degree[maxn],low[maxn]; vector<int>e[maxn]; void dfs(int u,int fa){ low[u]=++dfn; for(int i=0;i<e[u].size();i++){ int v=e[u][i]; if(v==fa)continue; if(!low[v])dfs(v,u); low[u]=min(low[u],low[v]); } } int tarjan(){ for(int i=1;i<=n;i++){ for(int j=0;j<e[i].size();j++){ if(low[i]!=low[e[i][j]])degree[low[i]]++; } } int res=0; for(int i=1;i<=n;i++)if(degree[i]==1)res++; return res; } int main(){ while(~scanf("%d %d",&n,&m)){ for(int i=0;i<=n;i++)degree[i]=0,e[i].clear(),low[i]=0; while(m--){ int a,b; scanf("%d %d",&a,&b); e[a].pb(b); e[b].pb(a); } dfn=0; dfs(1,-1); int ans=tarjan(); cout<<(ans+1)/2<<endl; } return 0; }
Railway
题意:给你一张图;
求桥的个数,联通分量有多个圈,圈里的边的数量;
dfs解决桥的个数,然后遇到割点,说明构成一个联通块,统计一下这个联通块的点数和边数;
#include<bits/stdc++.h> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back #define pf push_front #define fi first #define se second 11 typedef long long ll; typedef unsigned long long ull; typedef long double ldb; typedef double db; const db PI=acos(-1.0); const ll INF=0x3f3f3f3f3f3f3f3fLL; const int inf=0x3f3f3f3f;//0x7fffffff; const double eps=1e-9; const ll MOD=9999991; const int maxn=1e4+5; int n,m,dfn,bridge,cnt; struct edge{int u,v;edge(int a,int b){u=a,v=b;}}; vector<edge>e[maxn]; int num[maxn],low[maxn]; stack<edge>stk; set<int>point; int ans; void dfs(int u,int fa){ num[u]=low[u]=++dfn; for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(!num[v]){ stk.push(e[u][i]); dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=num[u]){ edge tmp(edge(1,1)); int cnt=0; point.clear(); do { cnt++; tmp=stk.top(); stk.pop(); point.insert(tmp.u); point.insert(tmp.v); }while(tmp.u!=u||tmp.v!=v); if(cnt>point.size())ans+=cnt; } if(low[v]>num[u])bridge++; } else if(num[v]<num[u]&&v!=fa){ stk.push(e[u][i]); low[u]=min(low[u],num[v]); } } } int main(){ while(~scanf("%d %d",&n,&m),n+m){ while(!stk.empty())stk.pop(); for(int i=0;i<=n;i++)e[i].clear(),num[i]=0,low[i]=0; while(m--){ int a,b; scanf("%d %d",&a,&b); e[a].pb(edge(a,b)); e[b].pb(edge(b,a)); } dfn=0,bridge=0,ans=0; // dfs(1,-1); for(int i=1;i<=n;i++) if(!num[i])dfs(i,-1); // cout<<"test"<<endl; cout<<bridge<<" "<<ans<<endl; } // system("pause"); return 0; }