题意:
给一个竞赛图,将图分成两部分,判断两部分的图是否符合传递闭包,a->b,b->c,则a->c
解法:
判定 —— P图 && Q图无环,P图 && ~Q图无环。
因为P图中必须无环,Q图中必须无环。
并且P中 点A可到达点B ,则点A和点B中间有一条边,因此如果不符合题意的话,即A可到达B,但A和B之间没有连边。
因此Q中 A和B 一定有一条边,因此 P图 && ~Q图中有环。
代码1:【对于图中环的判定】【1000ms以内】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int M = 2016*2016+100;
const int N = 2500;
struct Edge{
int to,next;
}e[2][M];
int head[2][N],tot1,tot2,n,dg[2][N];
char s[N];
void init()
{
tot1 = tot2 = 1;
rep(i,1,n) head[0][i] = head[1][i] = 0;
rep(i,1,n) dg[0][i] = dg[1][i] = 0;
}
void add(int x,int y,int idx)
{
if(idx == 0){
e[0][++tot1].to = y; e[0][tot1].next = head[0][x]; head[0][x] = tot1;
dg[0][y]++;
}
else{
e[1][++tot2].to = y; e[1][tot2].next = head[1][x]; head[1][x] = tot2;
dg[1][y]++;
}
}
//拓扑排序判断有向图中有无环
int solve(int idx)
{
queue<int> q;
while(q.size()) q.pop();
rep(i,1,n)
if(!dg[idx][i]) q.push(i);
int cnt = 0;
while(q.size())
{
int x = q.front();
q.pop();
cnt++;
for(int i = head[idx][x]; i ; i = e[idx][i].next)
{
int y = e[idx][i].to;
dg[idx][y]--;
if(dg[idx][y] == 0) q.push(y);
}
}
// printf("cnt: %d\n",cnt);
if(cnt == n) return 0;
else return 1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
rep(i,1,n)
{
scanf("%s",s+1);
rep(j,1,n)
{
if(s[j] == 'P' || s[j] == 'Q')
add(i,j,0);
if(s[j] == 'P')
add(i,j,1);
else if(s[j] == 'Q')
add(j,i,1);
}
}
/* for(int i = head[0][1]; i ; i = e[0][i].next){
printf("i:%d 1->to: %d\n",i,e[0][i].to);
}*/
if(solve(0) || solve(1)) printf("N\n");
else printf("T\n");
}
return 0;
}
代码2:直接bfs判断是否满足传递闭包性质【3000+ms】
【如果bfs是用前向星存图则为5000+ms,用vector存图则为3000+ms,原因不详】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <ctime>
#include <vector>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int M = 2016*2016+100;
const int N = 2500;
const int inf = -1;
vector<int> v1[N],v2[N];
int n,book[N],vis[N];
char s[N];
inline int gi()
{
int date = 0,m = 1; char ch = 0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
if(ch=='-'){m = -1; ch = getchar();}
while(ch>='0' && ch<='9')
{
date = date*10+ch-'0';
ch = getchar();
}return date*m;
}
inline int solve1(int x)
{
rep(i,0,n) book[i] = 0;
for(int k = v1[x].size()-1; k >= 0; k--)
{
book[v1[x][k]] = 1;
}
queue<int> q;
q.push(x);
while(q.size())
{
int y = q.front();
q.pop();
for(int i = v1[y].size()-1; i >= 0; i--)
{
int h = v1[y][i];
if(book[h] == 0){
return 0;
}
else if(book[h] < 2){
book[h]++;
q.push(h);
}
}
}
return 1;
}
inline int solve2(int x)
{
rep(i,0,n) book[i] = 0;
for(int k = v2[x].size()-1; k >= 0; k--)
{
book[v2[x][k]] = 1;
}
queue<int> q;
q.push(x);
while(q.size())
{
int y = q.front();
q.pop();
for(int i = v2[y].size()-1; i >= 0; i--)
{
int h = v2[y][i];
if(book[h] == 0){
return 0;
}
else if(book[h] < 2){
book[h]++;
q.push(h);
}
}
}
return 1;
}
int main()
{
int T;
T = gi();
while(T--)
{
n = gi();
rep(i,1,n)
{
v1[i].clear();
v2[i].clear();
}
rep(i,1,n)
{
scanf("%s",s+1);
rep(j,1,n)
{
if(s[j] == 'P'){
v1[i].push_back(j);
}
else if(s[j] == 'Q'){
v2[i].push_back(j);
}
}
}
int jud = 1;
rep(i,1,n)
{
if(!solve1(i))
{
jud = 0; break;
}
}
if(jud == 1)
{
rep(i,1,n)
{
if(!solve2(i))
{
jud = 0; break;
}
}
}
if(jud == 1) printf("T\n");
else printf("N\n");
}
return 0;
}