hdu 6165 FFF at Valentine

来源:互联网 发布:大富豪棋牌免费源码 编辑:程序博客网 时间:2024/06/05 15:36

Problem

acm.hdu.edu.cn/showproblem.php?pid=6165

Meaning

给出一幅 n 个点、m 条边的有向图,问是否对于图上任意两个点 a 和 b,都能从其中一个点出发到另一个点。

Analysis

把强连通分量缩点后,如果得到的是“链”(可以有一些分支,但必须从链内点出发指回链内结点,且方向都是相同的)就满足。
可以在缩点后判最长链上的点数是否等于全部点数。

Code

#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <stack>using namespace std;const int N = 1000, M = 6000;int head[N+1], from[M], to[M], nxt[M];void add_edge(int f, int t, int sz){    from[sz] = f;    to[sz] = t;    nxt[sz] = head[f];    head[f] = sz;}int dfn[N+1], low[N+1], tm;int belong[N+1], num;bool instk[N+1];stack<int> stk;void tarjan(int v){    dfn[v] = low[v] = ++tm;    stk.push(v);    instk[v] = true;    for(int i = head[v]; ~i; i = nxt[i])        if(!dfn[to[i]])        {            tarjan(to[i]);            low[v] = min(low[v], low[to[i]]);        }        else if(instk[to[i]])            low[v] = min(low[v], dfn[to[i]]);    if(dfn[v] == low[v])    {        ++num;        int t;        do        {            t = stk.top();            stk.pop();            instk[t] = false;            belong[t] = num;        } while(t != v);    }}int dis[N+1];bool inq[N+1];queue<int> que;int bfs(int s, int n){    memset(dis, 0, sizeof dis);    memset(inq, false, sizeof inq);    dis[s] = 1;    inq[s] = true;    que.push(s);    for(int tp; !que.empty(); que.pop())    {        tp = que.front();        inq[tp] = false;        for(int i = head[tp]; ~i; i = nxt[i])            if(dis[to[i]] < dis[tp] + 1)            {                dis[to[i]] = dis[tp] + 1;                if(!inq[to[i]])                {                    inq[to[i]] = true;                    que.push(to[i]);                }            }    }    int res = 0;    for(int i = 1; i <= n; ++i)        if(dis[i] > res)            res = dis[i];    return res;}int in[N+1]; // 缩点后点的入度int main(){    int T;    scanf("%d", &T);    while(T--)    {        int n, m;        scanf("%d%d", &n, &m);        memset(head, -1, sizeof head);        for(int i = 0, f, t, sz = 0; i < m; ++i)        {            scanf("%d%d", &f, &t);            add_edge(f, t, sz++);        }        // tarjan 缩点        memset(dfn, 0, sizeof dfn);        memset(instk, false, sizeof instk);        tm = num = 0;        for(int i = 1; i <= n; ++i)            if(!dfn[i])                tarjan(i);        // 重新构图        memset(head, -1, sizeof head);        memset(in, 0, sizeof in);        for(int i = 0, f, t, sz = 0; i < m; ++i)        {            f = from[i], t = to[i];            if(belong[f] != belong[t])            {                add_edge(belong[f], belong[t], sz++);                ++in[belong[t]];            }        }        // 找入度为 0 的点当出发点        int beg = -1;        for(int i = 1; i <= num; ++i)            if(!in[i])                if(~beg) // 有多个 0 入度点不行                {                    beg = -1;                    break;                }                else                    beg = i;        // BFS 找最长链        if(~beg && num == bfs(beg, num))            puts("I love you my love and our love save us!");        else            puts("Light my fire!");    }    return 0;}
原创粉丝点击