http://acm.hdu.edu.cn/showproblem.php?pid=5961
Problem 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
思路: f l o y d floyd floyd可以在 O ( n 3 ) O(n^3) O(n3)内求出传递闭包,但是时间复杂度太高了。传递性的定义:对于任意三个顶点 u , v , w u,v,w u,v,w,如果 u − > v u->v u−>v且 v − > w v->w v−>w那么一定有 u − > w u->w u−>w,根据这个定义不难发现 d f s dfs dfs就可以判断一个图是否具有传递性,在 d f s dfs dfs中多记录一个上次访问的结点,设为 p r e pre pre,当前正在访问的结点,设为 c u r cur cur,那么已知: p r e − > c u r pre->cur pre−>cur,只要对于任意的 u − > p r e u->pre u−>pre均有 u − > c u r u->cur u−>cur成立,不就能保证传递性了么,怎么得到 u u u呢,建一个反图就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=3005;
vector<int> vec[maxn];
vector<int> rvec[maxn];
bool vis[maxn];
char s[maxn][maxn];
int n,t;
void init()
{
for(int i=0;i<n;i++)
vec[i].clear(),rvec[i].clear();
memset(vis,0,sizeof(vis));
}
bool dfs(int pre,int cur,char ch)
{
int len=rvec[pre].size();
int tmp;
for(int i=0;i<len;i++)//判断传递性
{
tmp=rvec[pre][i];
// cout<<tmp<<' '<<pre<<' '<<cur<<' '<<s[tmp][cur]<<' '<<ch<<endl;
if(s[tmp][cur]!=ch)
return 0;
}
vis[cur]=1;
len=vec[cur].size();
for(int i=0;i<len;i++) //dfs判断每一个结点
if(!vis[vec[cur][i]]&&!dfs(cur,vec[cur][i],ch))
return 0;
return 1;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
init();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(s[i][j]=='P')
vec[i].push_back(j),rvec[j].push_back(i);//原图和反图
bool flag=1;
for(int i=0;i<n;i++)
if(vec[i].size()!=0&&!dfs(i,i,'P'))
flag=0;
if(!flag)
{
printf("N\n");
continue;
}
init();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(s[i][j]=='Q')
vec[i].push_back(j),rvec[j].push_back(i);
for(int i=0;i<n;i++)
if(vec[i].size()!=0&&!dfs(i,i,'Q'))
flag=0;
if(flag)
printf("T\n");
else
printf("N\n");
}
return 0;
}