POJ 1236 tarjan+缩点

题意:

N(2<N<100) 各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校 最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

题解:

看网上一位大牛说的很好,

第一个答案是入度为0的强连通块数。

因为首先,入度为0的强连通块因为没有人可以传给他信息,所以一定是答案。而其他点因为有入度所以有强通块可以传给。

而如果这个父亲没有入度,那么一定在之前已经给过他东西了;如果有入度,那么就可以以此类推到爷爷,一定有答案。

第二个答案是max(入读为0的点,出度为0的点)。

因为如果两个一样大,正好两两配对。如果不一样大,那么一样个数的点可以两两配对;而多出来的点一定要给它加边让他连上普通点。

一个点的时候特判,其余没了。

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cmath>
#include <map>
#include <string>
#include <stack>
#include <queue>

using namespace std;
const int MAXN=1e5+10;
struct node
{
    int v;
    int nxt;
};
node edge[MAXN];//边数
int ans1=0,ans2=0;
int head[MAXN];
int n,m;
int Stop,Bcnt,Dindex;//栈头,强通块数,时间戳
int DFN[MAXN],LOW[MAXN];//首时间戳,最近回溯点(根)
int Stap[MAXN];//答案栈
int instack[MAXN];//是否在栈中
int Belong[MAXN];//这个点属于第几个强连通块(点)
int cnt=0;
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    cnt++;
}
void tarjan(int i)
{
    int j;
    DFN[i]=LOW[i]=++Dindex;
    instack[i]=1;
    Stap[++Stop]=i;
    for (int e=head[i]; e!=-1; e=edge[e].nxt)
    {
        j=edge[e].v;
        if (!DFN[j])//儿子没遍历
        {
            tarjan(j);//遍历
            if (LOW[j]<LOW[i])//如果儿子已经形成环
                LOW[i]=LOW[j];//父亲也要在回溯的时候进入环
        }
        else if (instack[j]&&DFN[j]<LOW[i])//邻接的在栈里,所以是大大
            LOW[i]=DFN[j];//把这个点归到大大那
    }
    if (DFN[i]==LOW[i])//这个点的根是自己
    {
        Bcnt++;//多了一个强连通分量
        do
        {
            j=Stap[Stop--];//退栈
            instack[j]=0;//标记
            Belong[j]=Bcnt;//标记
        }
        while (j!=i);//亦可做LOW[j]!=DFN[j],如果到根,两个条件同时成立
    }
}
void solve()
{
    int i;
    Stop=Bcnt=Dindex=0;//栈头,强通块数,时间戳
    memset(DFN,0,sizeof(DFN));
    memset(LOW,0,sizeof(LOW));
    for (int i=1; i<=n; i++)
        if (!DFN[i])
            tarjan(i);

    int in[MAXN],out[MAXN];
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for (int i=1;i<=n;i++)
    {
        for (int j=head[i];j!=-1;j=edge[j].nxt)
        {
            if (Belong[i]!=Belong[edge[j].v])
            {
                ++out[Belong[i]];
                ++in[Belong[edge[j].v]];
            }
        }
    }
    int A=0,B=0;
    for (int i=1;i<=Bcnt;i++)
    {
        if (!in[i]) A++;
        if (!out[i]) B++;
    }
//    printf ("A==%d B==%d\n",A,B);
    if (Bcnt==1)
    printf ("1\n0\n");
    else printf ("%d\n%d\n",A,max(A,B));
}
int main()
{
    while (scanf ("%d",&n)!=EOF)
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        for (int i=1;i<=n;i++)
        {
            int t1;
            while (scanf ("%d",&t1)&&t1)
            {
                add_edge(i,t1);
            }
        }
        solve();
    }
    return 0;
}

 

posted on 2016-07-27 16:49  very_czy  阅读(176)  评论(0编辑  收藏  举报

导航