Description
我们称一个有向图G是传递的,当且仅当对任意三个不同的顶点a,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。
现在,给你两个有向图P = (V,Ep)和Q = (V,Ee),满足:
- EP与Ee没有公共边;
- (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
题目大意
判断两个图是否是传递的(它不过是把两个图用一个矩阵表示了),如果都是传递的输出T否则输出N
解题思路
判断传递…由传递的定义m[i][j]+m[j][z]->m[i][z]
也差不多只能暴力了,枚举每一个点,bfs判断该点与该点走两条边能到的一点是否有一条路直接相连
AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
vector<int>pp[2020];
vector<int>qq[2020];
bool vis[2020];//预标记直接相连的点
int n;
bool ans1(int ne)
{
queue<int> w;
memset(vis,0,sizeof(vis));
for(int i=0; i<pp[ne].size(); ++i)
{
vis[pp[ne][i]]=1;
w.push(pp[ne][i]);
}
while(!w.empty())
{
int y=w.front();
w.pop();
for(int i=0;i<pp[y].size();++i)
if(vis[pp[y][i]]==0)
return 0;
}
return 1;
}
bool ans2(int ne)
{
queue<int> w;
memset(vis,0,sizeof(vis));
for(int i=0; i<qq[ne].size(); ++i)
{
vis[qq[ne][i]]=1;
w.push(qq[ne][i]);
}
while(!w.empty())
{
int y=w.front();
w.pop();
for(int i=0;i<qq[y].size();++i)
if(vis[qq[y][i]]==0)
return 0;
}
return 1;
}
int main()
{
int t;
char x;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<=n;++i)
{
pp[i].clear();
qq[i].clear();
}
for(int i=1; i<=n; ++i)
{
getchar();
for(int j=1; j<=n; ++j)
{
scanf("%c",&x);
if(x=='P')
pp[i].push_back(j);
else if(x=='Q')
qq[i].push_back(j);
}
}
int ans=1;
for(int i=1; i<=n; ++i)
{
if(ans1(i)==0)
ans=0;
}
for(int i=1; i<=n; ++i)
{
if(ans2(i)==0)
ans=0;
}
if(ans)
printf("T\n");
else
printf("N\n");
}
}