Problem Description
我们称一个有向图G是传递的,当且仅当对任意三个不同的顶点a,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。
现在,给你两个有向图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。
注:在样例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;
}