HDU 6165 FFF at Valentine(Tarjan缩点+拓扑排序)

FFF at Valentine

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

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

3

5 5

1 2

2 3

2 4

3 5

4 5

3 3

1 2

2 3

3 1

5 5

1 2

2 3

3 1

3 4

4 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!

题目链接:HDU 6165

似乎比较模版的一道题目,一开始以为是一旦某个缩点后的点的出度超过2就不行了,实际上是可以的,比如$1 \to 2$,$2 \to 3$,$1 \to 3$,这样是三个连通分量且1的出度为2,但是任意取两个点$a,b$还是可以从$a$到达$b$或者$b$到达$a$的,因此更进一步应该是考虑拓扑序上是否同时存在两个可行的点,如果存在说明可以走分岔路这样一来至少分岔路上的两个点就是无法到达的

代码:

#include <stdio.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 10010;
const int M = 60010;
struct edge
{
    int to, nxt;
} E[M], e[M];
int head[N], tot;
int dfn[N], low[N], st[N], ins[N], scc, in[N], belong[N], ts, top;
int n, m;
int H[N], Tot;

void init()
{
    CLR(head, -1);
    tot = 0;
    CLR(dfn, 0);
    CLR(low, 0);
    CLR(ins, 0);
    scc = 0;
    CLR(in, 0);
    ts = top = 0;
    CLR(H, -1);
    Tot = 0;
}
inline void add(int s, int t)
{
    E[tot].to = t;
    E[tot].nxt = head[s];
    head[s] = tot++;
}
inline void Add(int s, int t)
{
    e[Tot].to = t;
    e[Tot].nxt = H[s];
    H[s] = Tot++;
}
void Tarjan(int u)
{
    dfn[u] = low[u] = ++ts;
    ins[u] = 1;
    st[top++] = u;
    int v;
    for (int i = head[u]; ~i; i = E[i].nxt)
    {
        v = E[i].to;
        if (!dfn[v])
        {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u])
    {
        ++scc;
        do
        {
            v = st[--top];
            ins[v] = 0;
            belong[v] = scc;
        } while (u != v);
    }
}
int solve()
{
    queue<int>Q;
    int i, j;
    for (i = 1; i <= n; ++i)
        if (!dfn[i])
            Tarjan(i);
    for (i = 1; i <= n; ++i)
    {
        for (j = head[i]; ~j; j = E[j].nxt)
        {
            int v = E[j].to;
            if (belong[v] == belong[i])
                continue;
            ++in[belong[v]];
            Add(belong[i], belong[v]);
        }
    }
    for (i = 1; i <= scc; ++i)
        if (!in[i])
            Q.push(i);
    while (!Q.empty())
    {
        if (Q.size() >= 2)
            return 0;
        int u = Q.front();
        Q.pop();
        for (int i = H[u]; ~i; i = e[i].nxt)
        {
            int v = e[i].to;
            if (--in[v] == 0)
                Q.push(v);
        }
    }
    return 1;
}
int main(void)
{
    int T, a, b;
    scanf("%d", &T);
    while (T--)
    {
        init();
        scanf("%d%d", &n, &m);
        while (m--)
        {
            scanf("%d%d", &a, &b);
            add(a, b);
        }
        solve() ? puts("I love you my love and our love save us!") : puts("Light my fire!");
    }
    return 0;
}
时间: 2024-08-29 13:05:08

HDU 6165 FFF at Valentine(Tarjan缩点+拓扑排序)的相关文章

2017 Multi-University Training Contest - Team 9 1005&amp;&amp;HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】

FFF at Valentine Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1060    Accepted Submission(s): 506 Problem Description At Valentine's eve, Shylock and Lucar were enjoying their time as any oth

HDU 6165 FFF at Valentine

题目大意:给出一个有向图,问你这个图中是否对于任意两点\(u,v\),都至少满足\(u\to v\)(\(u\)可到达\(v\),下同)或\(v\to u\)中的一个. 一看就是套路的图论题,我们先把边连起来. 考虑一个很基本的性质:在一个强连通分量的点两两可达 于是肯定先Tarjan缩一波点.然后我们得到了一个DAG 接下来就是考虑是否有两个点(当然是缩点之后的了)互不可达. 这个可以直接跑一边拓扑排序.然后看一下是否在某个时刻有两个点的入度为零即可. CODE #include<cstdio

[模板]tarjan缩点+拓扑排序

题目:给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 题目简述:先tarjan缩点,再从入度为零处进行一次拓扑排序,求最长路即可,话说拓扑排序求最长路真方便... 注意: 要明确拓扑的写法,要用栈写最优. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define man 100010 4 inline i

[ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)

题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓扑序DP,要去掉所有的重边. Code #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100008; struct sj{int to,next;}a[maxn*10]; ll mo

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

UVA 11324.The Largest Clique tarjan缩点+拓扑dp

题目链接:https://vjudge.net/problem/UVA-11324 题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以). 思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以).把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径.拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0

POJ 3114 - Countries in War(强连通分量+缩点+拓扑排序+DAG最短路)

Countries in War Time Limit:1000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u Appoint description: Description In the year 2050, after different attempts of the UN to maintain peace in the world, the third world war broke out. The impor

POJ2762 Going from u to v or from v to u? 强连通分量缩点+拓扑排序

题目链接:https://vjudge.net/contest/295959#problem/I 或者 http://poj.org/problem?id=2762 题意:输入多组样例,输入n个点和m条有向边,问该图中任意两点x, y之间是否满足x可以到y或者y可以到x. 一开始WA的原因是因为没注意到是或者, 如果是并且的话,就是一道简单的强连通分量的题,直接判断整个图是否为一个强连通分量 对于该题, 先用强连通分量进行缩点,简化图.图就变成了DAG,用拓扑排序判断图中点的入度, 图中入度为0

POJ 2762判断单联通(强连通缩点+拓扑排序)

Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14789   Accepted: 3915 Description In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors