杭电 1269 连通图模板

//自己理解着又敲了一遍代码,发现就是那回事,我希望自己能写写题解,一方便自己看,二方便别人理解
//但诚挚地说,我现在还不明白连通图,只是跟着学长思路走了一遍,至于如果我自己第一次看到这个题,我是不会想到连通图的
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<vector>//头文件,之后用来申请数组,这一点可能我理解的不清楚,只会比葫芦画瓢
using namespace std;
#define min(a, b) a<b?a:b
#define N 10010
vector<vector<int> >G;//学长说这个比下面那一行的方式好,可我也不知道为什么
//vector<int>G[N];
int n, m;
int visit[N], rode[N];//visit用来表示访问的第几个数,rode用来存最短的距离
int Stack[N];//自己建立栈
bool Instack[N];// 判断是否在栈里面
int Time, top;
int num, cnt;//强连通图:(大家可以百度)是有向图,且对于图中任意两个不同的顶点i和j,都存在从i到j的路径,则称是强连通图;强连通图只有一个强连通分量。
//故若判断小希是否都能到达所有房间,就是判断这个图是不是强连通图。也就是判断cnt是否等于1,且cnt=1时num是否等于n;cnt==1&&num==n代表图有一个连通分量且是他自身。即这是强连通图;
//若不是强连通图,这道题是有向图,则称为“非强连通的有向图” 而它的连通分量可能有若干个
void Init()//初始化,在需要很多处是滑的时候最好写在一个专有的函数里,方便检查Init  initially(初始化)
{
    G.clear();//清空
    G.resize(n+1);//申请内存 //忘记申请内存了(这是我自己打的时候出现的错误)
    memset(visit, 0, sizeof(visit));
    memset(rode, 0, sizeof(rode));
    memset(Stack, 0, sizeof(Stack));
    memset(Instack, false, sizeof(Instack));
    num=cnt=Time=top=0;
}
void Tarjan(int u)
{
    visit[u]=rode[u]=++Time;//visit和rode从1开始
    Stack[top++]=u;//入栈
    Instack[u]=true;//表明在栈里面了
    int len=G[u].size();//看有多少在那个里面 //这里写错了(这是我自己打的时候出现的错误)
    int v;
    for(int i=0; i<len; i++)
    {
        v=G[u][i];// 数组里面的第几个 //看来对那个不熟悉(这是我自己打的时候出现的错误)
        if(!visit[v])//其实也可以这样写if(!rode[v]),无非就是判断这个点是否访问过,没有访问过时visit[v] rode[v]都为0;
        {
            Tarjan(v);//递归,这种算法叫做Tarjan,你们可以上网搜搜加深理解
            rode[u]=min(rode[u], rode[v]);//当回朔时,就更改u也就是父亲的最短路径,因为儿子v的是最先更新的;
            //原因如下:因为递归到最后如果有“连通块”就会执行 else if 例如1->2->3->1;当执行到3->1时就会因为1已经在栈里面,而执行else if
            
        }
        else if(Instack[v])
        {
            rode[u]=min(rode[u], visit[v]);//其实写成rode[u]=min(rode[u], rode[v]);也是可以的,学长说当求割点时必须这样写;
        }
    }
    if(rode[u]==visit[u])
    {
        do
        {
            num++;
            v=Stack[--top];
            Instack[v]=false;
        }while(u!=v);//do while 会更简单吧,第一次用 do while
        cnt++;
    }
}
void solve()
{
    Tarjan(1);
    if(cnt==1&&num==n)
        puts("Yes");
    else
        puts("No");
}
int main()
{
    while(scanf("%d%d", &n, &m), n+m)
    {
        Init();
        int a, b;
        while(m--)
        {
            scanf("%d%d", &a, &b);
            G[a].push_back(b);
        }
        solve();
    }
    return 0;
}
posted @ 2015-08-05 19:38  花开须臾  阅读(198)  评论(0编辑  收藏  举报