HDU5961 传递(拓扑排序判环)

版权声明:欢迎转载~转载请注明出处! https://blog.csdn.net/riba2534/article/details/83314881

Problem Description

我们称一个有向图G是传递的,当且仅当对任意三个不同的顶点a,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。
img
现在,给你两个有向图P = (V,Ep)和Q = (V,Ee),满足:
\1. EP与Ee没有公共边;
\2. (V,Ep⋃Ee)是一个竞赛图。
你的任务是:判定是否P,Q同时为传递的。

Input

包含至多20组测试数据。
第一行有一个正整数,表示数据的组数。
对于每组数据,第一行有一个正整数n。接下来n行,每行为连续的n个字符,每 个字符只可能是’-’,’P’,’Q’中的一种。
∙如果第i行的第j个字符为’P’,表示有向图P中有一条边从i到j;
∙如果第i行的第j个字符为’Q’,表示有向图Q中有一条边从i到j;
∙否则表示两个图中均没有边从i到j。
保证1 <= n <= 2016,一个测试点中的多组数据中的n的和不超过16000。保证输入的图一定满足给出的限制条件。

Output

对每个数据,你需要输出一行。如果P! Q都是传递的,那么请输出’T’。否则, 请输出’N’ (均不包括引号)。

Sample Input

4
4
-PPP
--PQ
---Q
----
4
-P-P
--PQ
P--Q
----
4
-PPP
--QQ
----
--Q-
4
-PPP
--PQ
----
--Q-

Sample Output

T
N
T
N

Hint

在下面的示意图中,左图为图为Q。

img

注:在样例2中,P不是传递的。在样例4中,Q不是传递的。

思路

题目已经给出如何判断一个图是传递的.

当这个图为传递的,两个子图要满足两个条件:

  • P+Q的合图无环
  • P+Q的反图(即Q图重的方向改成反向)的合图无环

使用拓扑排序判环即可

代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
const int N = 2020;
vector<int> e1[N];
vector<int> e2[N];
char s[N][N];
int vis[N], n;
bool dfs1(int u)
{
    vis[u] = -1;
    for (auto v : e1[u])
    {
        if (vis[v] < 0)
            return false;
        else if (!vis[v] && !dfs1(v))
            return false;
    }
    vis[u] = 1;
    return true;
}
bool dfs2(int u)
{
    vis[u] = -1;
    for (auto v : e2[u])
    {
        if (vis[v] < 0)
            return false;
        else if (!vis[v] && !dfs2(v))
            return false;
    }
    vis[u] = 1;

    return true;
}
bool topsort1()
{

    mem(vis, 0);
    for (int u = 1; u <= n; u++)
        if (!vis[u])
            if (!dfs1(u))
                return false;
    return true;
}
bool topsort2()
{

    mem(vis, 0);
    for (int u = 1; u <= n; u++)
        if (!vis[u])
            if (!dfs2(u))
                return false;
    return true;
}
void solve()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        e1[i].clear();
        e2[i].clear();
    }
    for (int i = 1; i <= n; i++)
    {
        scanf("%s", s[i] + 1);
        for (int j = 1; j <= n; j++)
        {
            if (s[i][j] == 'P')
            {
                //puts("!!!");
                e1[i].push_back(j);
                e2[i].push_back(j);
            }
            else if (s[i][j] == 'Q')
            {
                e1[i].push_back(j);
                e2[j].push_back(i);
            }
        }
    }
    int f1 = topsort1(), f2 = topsort2();
    if (topsort1() && topsort2())
        puts("T");
    else
        puts("N");
}
int main()
{
    // freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while (t--)
        solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/riba2534/article/details/83314881