• ZOJ 2588 求割边问题


    题目链接:http://vjudge.net/problem/viewProblem.action?id=14877

    题目大意:

    要尽可能多的烧毁桥,另外还要保证图的连通性,问哪些桥是绝对不能烧毁的

    我们很容易看出不能烧毁的是必然是作为割边存在的桥。

    求割边,我们用Tarjan算法,这与求割点有点小区别在与,对于(u,v)的点low[v]>=dfn[u]时就表示u为割点,而low[v]>dfn[u]时才能说明(u,v)是一条割边

    因为这里要求出割边的序号,所以在写边的结构体时,用id代表桥的序号,我们每次得到a,b总会添加两条边a->b和b->a,因为这是无向图,所以这两条边公用一个id

    另外要注意的是这道题目允许两个地点有多条边出现,所以我们需要用一个tag标志位来注明是否有重边

    oid addPath(int a,int b,int c)
    {
        int i;
        for(i=first[a];i!=-1;i=path[i].next)
            if(path[i].y==b) break;
        if(i!=-1)//说明是重边
            path[i].tag=1;
        else{
            path[k].y=b,path[k].tag=0,path[k].next=first[a],path[k].id=c; first[a]=k;
            k++;
        }
    }

    每次深度搜索一个节点,不断更新上面的low值和dfn值,并找到low[v]>dfn[u]的边并将它们保存到bridge数组中,nbridge用来统计桥的数量

    void dfs(int u,int fa)
    {
        visit[u]=1,dfn[u]=low[u]=tmpdfn++;
        for(int i=first[u];i!=-1;i=path[i].next){
            int j=path[i].y;

            if(!visit[j]){
                dfs(j,u);
                low[u]=min(low[j],low[u]);
                if(low[j]>dfn[u]&&!path[i].tag)
                    bridge[++nbridge]=path[i].id;
            }
            else{
                if(j!=fa) low[u]=min(low[u],dfn[j]);//j已被访问且不是父亲节点,说明可以形成一条回边
            }
        }
    }

    总代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 10005
    #define M 100005
    int tmpdfn,k,nbridge,bridge[M],visit[N],dfn[N],low[N];
    int first[N];
    struct Path{
        int y,tag,id;
        int next;
    }path[2*M];
    
    void addPath(int a,int b,int c)
    {
        int i;
        for(i=first[a];i!=-1;i=path[i].next)
            if(path[i].y==b) break;
        if(i!=-1)//说明是重边
            path[i].tag=1;
        else{
            path[k].y=b,path[k].tag=0,path[k].next=first[a],path[k].id=c;
            first[a]=k;
            k++;
        }
    }
    
    void dfs(int u,int fa)
    {
        visit[u]=1,dfn[u]=low[u]=tmpdfn++;
        for(int i=first[u];i!=-1;i=path[i].next){
            int j=path[i].y;
    
            if(!visit[j]){
                dfs(j,u);
                low[u]=min(low[j],low[u]);
                if(low[j]>dfn[u]&&!path[i].tag)
                    bridge[++nbridge]=path[i].id;
            }
            else{
                if(j!=fa) low[u]=min(low[u],dfn[j]);//j已被访问且不是父亲节点,说明可以形成一条回边
            }
        }
    }
    int main()
    {
        int T,n,m,x,y;
        scanf("%d",&T);
    
        while(T--){
            scanf("%d%d",&n,&m);
            k=0,nbridge=0,tmpdfn=1;
            memset(first,-1,sizeof(first));
            memset(visit,0,sizeof(visit));
            memset(bridge,0,sizeof(bridge));
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&x,&y);
                addPath(x,y,i);
                addPath(y,x,i);
            }
            dfs(1,0);
            printf("%d
    ",nbridge);
            sort(bridge+1,bridge+nbridge+1);
            for(int i=1;i<nbridge;i++) printf("%d ",bridge[i]);
            if(nbridge>0) printf("%d
    ",bridge[nbridge]);
            if(T>0) printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    tiger-complier 问题记录 类型检查
    leetcode 854. K-Similar Strings
    FPO优化简介
    [转载]深入解析结构化异常处理
    再看链接-WIN
    管道控制Telnet
    管道 简介与简单使用
    Detours 简介与简单使用
    netStat逆向分析
    Fport逆向分析以及C++实现
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3885211.html
Copyright © 2020-2023  润新知