HDU 6165 FFF at Valentine (tarjan缩点+拓扑判任意两点联通)

来源:互联网 发布:淘宝模特张恋恋多大了 编辑:程序博客网 时间:2024/06/11 09:36


FFF at Valentine

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 786    Accepted Submission(s): 391


Problem Description

At Valentine's eve, Shylock and Lucar were enjoying their time as any other couples. Suddenly, LSH, Boss of FFF Group caught both of them, and locked them into two separate cells of the jail randomly. But as the saying goes: There is always a way out , the lovers made a bet with LSH: if either of them can reach the cell of the other one, then LSH has to let them go.
The jail is formed of several cells and each cell has some special portals connect to a specific cell. One can be transported to the connected cell by the portal, but be transported back is impossible. There will not be a portal connecting a cell and itself, and since the cost of a portal is pretty expensive, LSH would not tolerate the fact that two portals connect exactly the same two cells.
As an enthusiastic person of the FFF group, YOU are quit curious about whether the lovers can survive or not. So you get a map of the jail and decide to figure it out.
 

Input
Input starts with an integer T (T≤120), denoting the number of test cases.
For each case,
First line is two number n and m, the total number of cells and portals in the jail.(2≤n≤1000,m≤6000)
Then next m lines each contains two integer u and v, which indicates a portal from u to v.
 

Output
If the couple can survive, print “I love you my love and our love save us!”
Otherwise, print “Light my fire!”
 

Sample Input
35 51 22 32 43 54 53 31 22 33 15 51 22 33 13 44 5
 

Sample Output
Light my fire!I love you my love and our love save us!I love you my love and our love save us!
 

Source
2017 Multi-University Training Contest - Team 9
 

Recommend
liuyiding
 


  • 题意:

    • 给定一个有向图,n个点,m条边,无自环,无重边
    • 问:是否任意两点A,B,满足AB连通
  • 规模:

    • 2<=n<=1000,m<=6000
    • T<120

思路:1k点,6k边, 容易有环, tarjan缩点,然后就是一个DAG了(如果不联通, 肯定no), 然后分析得, 其实就是看能不能一条链可以把所有点穿起来, 如果有一个分叉, 处于两个分叉上的点就不能相互到达,但是这条链上可能有多出许多边, 干扰这条链, 问题就有点麻烦了。。

但是拓扑排序一下, 就完美的解决这个问题, 拓扑过程看是不是每一层都有一个入度为0的点, 也就是每一层是不是只有一个可以走的选择,如果每一层都是一个, 那么所有点走下来就是一条链了, 每次拓扑都把多余的边删掉了...太强了...


总结: 深刻理解拓扑, 拓扑可以判断是否可以一条链遍历所有点,可以在拓扑的过程中得出一些值, 比如万一让你找一个分叉,两个分叉的路径,也可以在拓扑路径中控制...考到有向图里的一些性质,一定想想拓扑排序

代码:

#include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <stack>#include <queue>#include <algorithm>using namespace std;const int maxn = 1e3 + 5;int n, m, low[maxn], dfn[maxn], id[maxn], scc_cnt, dfs_cnt, book[maxn][maxn];int in[maxn], out[maxn];vector<int> v[maxn], edge[maxn];stack<int> s;void init(){    memset(low, 0, sizeof(low));    memset(id, 0, sizeof(id));    memset(dfn, 0, sizeof(dfn));    memset(in, 0, sizeof(in));    memset(out, 0, sizeof(out));    memset(book, 0, sizeof(book));    scc_cnt = dfs_cnt = 0;    for(int i = 0; i < maxn; i++)        v[i].clear(), edge[i].clear();    while(!s.empty())        s.pop();}void tarjan(int x){    dfn[x] = low[x] = ++dfs_cnt;    s.push(x);    for(int i = 0; i < v[x].size(); i++)    {        int to = v[x][i];        if(!dfn[to])        {            tarjan(to);            low[x] = min(low[x], low[to]);        }        else if(!id[to])            low[x] = min(low[x], dfn[to]);    }    if(low[x] == dfn[x])    {        scc_cnt++;        while(1)        {            int u = s.top();            s.pop();            id[u] = scc_cnt;            if(x == u) break;        }    }}void scc(){    for(int i = 1; i <= n ; i++)        if(!dfn[i])            tarjan(i);}void build(){  for(int i = 1; i <= n; i++)    {        for(int j = 0; j < v[i].size(); j++)        {            int to = v[i][j];            if(id[i] != id[to] && !book[id[i]][id[to]])            {                edge[id[i]].push_back(id[to]);                book[id[i]][id[to]] = 1;                in[id[to]]++;            }        }    }}int Top_sort(){    queue<int> q;    for(int i = 1; i <= scc_cnt; i++)        if(!in[i])            q.push(i);    while(!q.empty())    {        if(q.size() != 1)            return 0;        int u = q.front(); q.pop();        for(int i = 0; i < edge[u].size(); i++)        {            int to = edge[u][i];            in[to]--;            if(in[to] == 0) q.push(to);        }    }    return 1;}int main(){    int t;    cin >> t;    while(t--)    {        init();        scanf("%d%d", &n, &m);        int x, y;        for(int i = 1; i <= m; i++)        {            scanf("%d%d", &x, &y);            v[x].push_back(y);        }        scc();        build();        puts(Top_sort() ? "I love you my love and our love save us!" : "Light my fire!");    }    return 0;}



阅读全文
0 0
原创粉丝点击