zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3885211.html
Copyright © 2011-2022 走看看