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;

}

 

你可能感兴趣的:(poj)