Hdu 5961 传递(bfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5961
解题思路:
题目最重要的一句话,如下图.
只有a->b,b->c,一定存在a->c,那么就很容易处理了,只要把a连接的所有点标记掉,那如果图是传递的,就不存在其他点能通过a连接的点到达,反之图就不是传递的,即如果bfs搜到了长度超过1的路径,就意味着图不是传递的。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 2025
struct Edge{
int from,to,nex;
}p[MAXN*MAXN],q[MAXN*MAXN];//邻近表
int ans,cnt;
int headp[MAXN],headq[MAXN];
int vis[MAXN];
char s[MAXN];
struct node{
int num,sum;//点,次数
}now;
bool flag;
int n;
inline void bfs(){//检查图P
for(int i=0;i<n;i++){
if(headp[i]!=-1){
memset(vis,0,sizeof(vis));
queue<node>que;
que.push(node{i,0});
while(!que.empty()){
now=que.front();
que.pop();
if(now.sum>=2){//如果sum>=2就意味着有一个点a->b,b->c,而a不能直接到c,那就是不符合题意的
flag=false;
return;
}
for(int j=headp[now.num];j!=-1;j=p[j].nex){
if(vis[p[j].to]==0){
vis[p[j].to]=1;//重点,其实就是为了标记起点连接的所有点
que.push(node{p[j].to,now.sum+1});
}
}
}
}
}
}
inline void bfs1(){//检查图Q
for(int i=0;i<n;i++){
if(headq[i]!=-1){
memset(vis,0,sizeof(vis));
queue<node>que;
que.push(node{i,0});
while(!que.empty()){
now=que.front();
que.pop();
if(now.sum>=2){
flag=false;
return;
}
for(int j=headq[now.num];j!=-1;j=q[j].nex){
if(vis[q[j].to]==0){
vis[q[j].to]=1;
que.push(node{q[j].to,now.sum+1});
}
}
}
}
}
}
int main() {
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
cnt=1,ans=1;
memset(headp,-1,sizeof(headp));
memset(headq,-1,sizeof(headq));
for(int i=0;i<n;i++){
scanf("%s",s);
for(int j=0;j<n;j++){
if(s[j]=='P'){
p[cnt].from=i;
p[cnt].to=j;
p[cnt].nex=headp[i];
headp[i]=cnt++;
}else if(s[j]=='Q'){
q[ans].from=i;
q[ans].to=j;
q[ans].nex=headq[i];
headq[i]=ans++;
}
}
}
flag=true;
bfs();
if(flag)bfs1();//优化,仅当图P是传递的才检查图Q
if(flag)printf("T\n");
else printf("N\n");
}
return 0;
}