• poj 1523 SPE 夜


    http://poj.org/problem?id=1523

    居然1A and 0ms  太让我意外了

    题目大意:

    给你几个电脑的双相连通图 问你是否存在割点 如果存在输出割点并输出此割点见原图变成了几个块

    输入输出只要注意就是了 没别的办法

    Tarjan 算法 我就不多说了 我也说不好

    总之用Tarjan算法找割点 但是你搜索时的根结点要特判

    对不每个割点用dfs求其可把原图分成几个块

    从割点发出可能用k个分支 那么块数 <= k

    对其分支进行深搜并记录 有几个分支可以向下搜 就有几个块

    深搜记录 可以搞定几个分支相连的情况

    详情见代码注释:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<algorithm>
    
    using namespace std;
    const int N=1005;
    const int M=10000005;
    struct node
    {
        struct tt *next;
    }mem[N];
    struct tt
    {
        struct tt *next;
        int j;
    };
    int had[N];//割点是否已保存
    int cutpoint[N];//保存割点
    int I;//割点数目
    int deep;//深度 (时间戳)
    bool visited[N];
    stack<int>str;
    bool in[N];
    int low[N];
    int dfn[N];
    int st;//开始搜的起始点
    void build(int i,int j)
    {
        struct tt *t=new tt;
        t->j=j;
        t->next=mem[i].next;
        mem[i].next=t;
    }
    void Clear()//每次对表头进行清理
    {
        for(int i=0;i<N;++i)
        mem[i].next=NULL;
    }
    void Tarjan(int x)
    {
        ++deep;
        low[x]=dfn[x]=deep;
        visited[x]=true;
        str.push(x);
        in[x]=true;
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(visited[t->j]==false)
            {
                Tarjan(t->j);
                low[x]=min(low[x],low[t->j]);
            }else if(in[t->j])
            {
                low[x]=min(low[x],dfn[t->j]);
            }
            if(!had[x]&&low[t->j]>=dfn[x]&&x!=st)//如果此点没记录 且为割点
            {//但是不能等于起始点 因为起始点得进行特判
              had[x]=true;
              cutpoint[I]=x;
              ++I;
            }
            t=t->next;
        }
        if(low[x]==dfn[x])//对以x为根的强连通图进行出栈处理
        {
            while(str.top()!=x)
            {
                in[str.top()]=false;
                str.pop();
            }
            in[str.top()]=false;
            str.pop();
        }
    }
    void dfs(int x)//深搜并记录
    {
        visited[x]=true;
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(visited[t->j]==false)
            dfs(t->j);
            t=t->next;
        }
    }
    int findnum(int x)
    {
        memset(visited,false,sizeof(visited));
        visited[x]=true;
        struct tt *t=mem[x].next;
        int num=0;
        while(t!=NULL)
        {
            if(visited[t->j]==false)//有多少分支是可搜的
            {
                ++num;
                dfs(t->j);
            }
            t=t->next;
        }
        return num;
    }
    int main()
    {
        int i,j;
        for(int w=1;;++w)
        {
            st=M;
            while(scanf("%d",&i),i)
            {
                scanf("%d",&j);
                if(st==M)
                st=j;
                build(i,j);
                build(j,i);
            }
            if(st==M)
            break;
            I=0;
            if(findnum(st)>1)//对起始点进行特判 看它有多少不相连分支
            {
                had[st]=true;
                cutpoint[I]=st;
                ++I;
            }
            deep=0;
            while(!str.empty())
            str.pop();
            memset(in,false,sizeof(in));
            memset(visited,false,sizeof(visited));
            memset(had,false,sizeof(had));
            Tarjan(st);
            printf("Network #%d\n",w);
            if(I==0)
            {
                printf("  No SPF nodes\n");
            }
            else
            {
                sort(cutpoint,cutpoint+I);
                for(int i=0;i<I;++i)
                {
                    printf("  SPF node %d leaves %d subnets\n",cutpoint[i],findnum(cutpoint[i]));
                }
            }
            printf("\n");
            Clear();
        }
        return 0;
    }
    

    更令我意外的是 直接用dfs 就能过 时间 16ms

    每次对每个点进行判定 如果从他出发的分支有多余一个是可搜的 则是割点 且有多少是可搜的 就有多少块

    其实就是对上面程序中对起始点特判的方法 无语了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<algorithm>
    
    using namespace std;
    const int N=1001;
    const int M=10000005;
    struct node
    {
        struct tt *next;
    }mem[N];
    struct tt
    {
        struct tt *next;
        int j;
    };
    int I;//割点数目
    bool visited[N];
    bool had[N];
    void build(int i,int j)
    {
        struct tt *t=new tt;
        t->j=j;
        t->next=mem[i].next;
        mem[i].next=t;
    }
    void Clear()//每次对表头进行清理
    {
        for(int i=0;i<N;++i)
        mem[i].next=NULL;
    }
    void dfs(int x)//深搜并记录
    {
        visited[x]=true;
        struct tt *t=mem[x].next;
        while(t!=NULL)
        {
            if(visited[t->j]==false)
            dfs(t->j);
            t=t->next;
        }
    }
    int findnum(int x)
    {
        memset(visited,false,sizeof(visited));
        visited[x]=true;
        struct tt *t=mem[x].next;
        int num=0;
        while(t!=NULL)
        {
            if(visited[t->j]==false)//有多少分支是可搜的
            {
                ++num;
                dfs(t->j);
            }
            t=t->next;
        }
       // cout<<x<<" "<<num<<endl;
        return num;
    }
    int main()
    {
        int i,j;
        for(int w=1;;++w)
        {
            memset(had,false,sizeof(had));
            j=-1;
            while(scanf("%d",&i),i)
            {
                scanf("%d",&j);
                had[i]=had[j]=true;
                build(i,j);
                build(j,i);
            }
            if(j==-1)
            break;
            printf("Network #%d\n",w);
            I=0;
            for(int i=1;i<N;++i)
            {
                if(had[i]==false)
                continue;
                int k=findnum(i);
                if(k>1)
                {
                    ++I;
                    printf("  SPF node %d leaves %d subnets\n",i,k);
                }
            }
            if(I==0)
            {
                printf("  No SPF nodes\n");
            }
            printf("\n");
            Clear();
        }
        return 0;
    }
    
  • 相关阅读:
    ASP.NET控件开发学习笔记第5回 HtmlTextWriter的相关枚举
    ASP.NET控件开发学习笔记第4回 为控件添加属性
    ASP.NET控件开发学习笔记第6回 ViewState
    构建可反转排序的泛型字典类(9完)完善
    ASP.NET控件开发学习笔记第一回 HelloWorld
    构建可反转排序的泛型字典类(7)实现IDictionary接口
    C#泛型专题系列文章目录导航
    构建可反转排序的泛型字典类(8)实现IDictionary接口
    ASP.NET控件开发学习笔记第二回 又见Hello World
    ASP.NET控件开发学习笔记第3回 自制导航控件
  • 原文地址:https://www.cnblogs.com/liulangye/p/2524260.html
Copyright © 2020-2023  润新知