POJ1236 Network of Schools 强连通+缩点

原创 2015年07月09日 17:49:51

题目链接:

poj1236




题意:

给出一幅有向图,给出图中所有的边。问:

1.要遍历完图的所有顶点,需要遍历多少次(可以从不同起点)

2.要想只遍历一次,经过图中所有顶点(强连通)最少 需要增加多少条边



题解思路:

首先就是缩点重新建图

对于问题1:

要遍历整个图,只需要从图的所有起点开始遍历

这里图中的起点就是入度为0的点,起点个数即为遍历次数。

对于问题2:

要想使原图成为强连通图

需要保证图中没有入度为0或出度为0的顶点;

而每增加一条边 的  最优连接策略 是   从一个出度为0的顶点到一个入度为0的顶点

这样 需要增加的最少边数即为   入度为0的顶点个数 和   出度为0的顶点个数   之间的最大值


另外需要注意图中只有一个强连通分量的特殊情况(重建图后只有一个顶点):

需要的遍历次数为1

需要的最少边数为0


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 105
using namespace std;
struct node{
    int to,next;
}edge[maxn*maxn];
int head[maxn];
int s;

int dfn[maxn],low[maxn],num;

int insta[maxn],sta[maxn],top;

int belong[maxn],block;
void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(insta,0,sizeof(insta));
    memset(belong,0,sizeof(belong));
    top=num=s=block=0;
}

void Tarjan(int u,int pre)
{
    dfn[u]=low[u]=++num;
    insta[u]=1;
    sta[top++]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(insta[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int d=-1;
        block++;
        while(d!=u)
        {
            d=sta[--top];
            insta[d]=0;
            belong[d]=block;
        }
    }
}

void rebuild(int n)
{
    int in[maxn]={0};
    int out[maxn]={0};
    int u,v;
    for(int i=1;i<=n;i++)
    {
        u=belong[i];
        for(int j=head[i];j!=-1;j=edge[j].next)
        {
            v=edge[j].to;
            v=belong[v];
            if(u!=v)
            {
                in[v]++;
                out[u]++;
            }
        }
    }
    int s1=0,s2=0;
    for(int i=1;i<=block;i++)
    {
        if(!in[i])
            s1++;
        if(!out[i])
            s2++;
    }
    if(s1==0)
        cout<<1<<endl;
    else
        cout<<s1<<endl;
    if(block==1)
        cout<<0<<endl;
    else
        cout<<max(s1,s2)<<endl;
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n,a,b;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            while(scanf("%d",&a)&&a)
            {
                edge[s]={a,head[i]};
                head[i]=s++;
            }
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                Tarjan(i,-1);
        rebuild(n);
    }
    return 0;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

poj1236

结构体排序~水过#include #include #include using namespace std; struct node { char name[21]; int all_sc...

poj1236 - Network of Schools

想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410              &...

【poj 1523】SPF 【Greater New York 2000】

Description Consider the two networks shown below. Assuming that data moves around these networks on...

HDU - 4685 Prince and Princess

There are n princes and m princesses. Princess can marry any prince. But prince can only marry the p...

Rman switch to copy

With RMAN you can create copy of live Database and perform the switch to copy when main database is ...

POJ1236----tarjan缩点

题目 一些学校通过网络连接在一起,每个学校手中有一份名单,即它所指向的点。学校A的名单中有学校B,并不能保证学校B的名单里有学校A。 现在有一软件。  1.问至少发给几个学校才能保证所有的学校都...

poj1236-Tarjan算法

poj1236--Tarjan算法 题目大意:     一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,那...

Problem J. Journey to the “The World’s Start”

存个代码 #include #include #include #include #define lson root*2,l,Mid #define rson root*2+1,Mid+1,...

bzoj 4034 [HAOI2015]树上操作

Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a 。 操作 2 :把某个节点 x 为根的子树...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)