联通分量

点双联通分量:没有割点;

边双联通分量:没有割边;

如何求无向图割点?

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;
}
View Code

Road Construction

 POJ - 3352 

给你一个无向图:问你最少加几条边,使得图成为双联通分量 ;

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;
}
View Code

Railway

 HDU - 3394 

题意:给你一张图;

求桥的个数,联通分量有多个圈,圈里的边的数量;

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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/littlerita/p/12405395.html
今日推荐