zoukankan      html  css  js  c++  java
  • 联通分量

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

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

    如何求无向图割点?

    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()!='
    '){
        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

    Financial Crisis

     HDU - 3749 

    题意:给你一个无向图,问你两个点,之间有几条路,

    没有路:不连通,用并查集解决;

    两条以上:在a,b,在一个点双联通分量里,并且,这个联通分量的点数要大于2;

    剩下的就是一条;

    解法:判断是不是在一个点联通分量,只需要记一下low数组,相同就在一个联通分量上,但麻烦的是你要记录这个联通分量。

    做法: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=5e3+5;
    int fa[maxn];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;}
    int n,m,q,dfn,bcnt;
    struct edge{int u,v;edge(int a,int b){u=a,v=b;}};
    vector<edge>e[maxn];
    int low[maxn],dep[maxn],color[maxn];
    vector<int>belong[maxn];
    stack<edge>stk;
    vector<int>bcc[maxn];
    void dfs(int u,int fa){
        dep[u]=low[u]=++dfn;
        for(int i=0;i<e[u].size();i++){
        int v=e[u][i].v;
        if(v==fa)continue;
        if(!low[v]){
            stk.push(e[u][i]);
            dfs(v,u);
        low[u]=min(low[u],low[v]);
        if(low[v]>=dep[u]){
        bcnt++;
        bcc[bcnt].clear();
        edge tmp(edge(1,1));
        while(1){
        tmp=stk.top();
        stk.pop();
        int x=tmp.u,y=tmp.v;
        if(color[x]!=bcnt){
        color[x]=bcnt,bcc[bcnt].pb(x),belong[x].pb(bcnt);
        }
        if(color[y]!=bcnt){
        color[y]=bcnt,bcc[bcnt].pb(y),belong[y].pb(bcnt);
        }
        if(x==u&&y==v)break;
        }
        }
        
        }
        else if(dep[v]<dep[u]&&v!=fa)low[u]=min(low[u],dep[v]);
        }
    }
    int main(){
        int cas=1;
        while(~scanf("%d %d %d",&n,&m,&q),n+m+q){
        dfn=0,bcnt=0;
        for(int i=0;i<n;i++)dep[i]=0,color[i]=0,belong[i].clear(),e[i].clear(),fa[i]=i,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));
        build(a,b);
        }
        for(int i=0;i<n;i++)if(!low[i])dfs(i,-1);
        printf("Case %d:
    ",cas++);
        while(q--){
        int a,b;
        scanf("%d %d",&a,&b);
        if(find(a)!=find(b))cout<<"zero"<<endl;
        else {
        int flag=0;
        for(int i=0;i<belong[a].size()&&!flag;i++)
        for(int j=0;j<belong[b].size()&&!flag;j++){
        if(belong[a][i]==belong[b][j]){
        int num=belong[a][i];
        if(bcc[num].size()>2)flag=1,cout<<"two or more"<<endl;
        }
        }
        if(!flag)cout<<"one"<<endl;
        } 
       
        }
        
        }
        // system("pause");
        return 0;
    }
    View Code
    想的太多,做的太少;
  • 相关阅读:
    顺时针打印矩阵
    topK问题
    9. Palindrome Number(回文数)
    Spinner用法详解
    翻转字符串
    清雨的自助餐(斐波那契数列的应用)
    2. Add Two Numbers(链表尾插法)
    assign和weak的区别
    14-最长公共前缀
    12 13-int与罗马数字转换
  • 原文地址:https://www.cnblogs.com/littlerita/p/12405395.html
Copyright © 2011-2022 走看看