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;
}

 

转载于:https://www.cnblogs.com/liulangye/archive/2012/05/29/2524260.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值