http://acm.split.hdu.edu.cn/showproblem.php?pid=4324
题意:有n个人,u和v之间的关系有且仅有u喜欢v和v喜欢u中的一种。在要求其中是否存在三角关系。
题解:由于每两个人之间都有关系,即有向边。那么对于环就肯定存在三角关系。比如a->b->c->d->a,根据题意,对于a和c肯定存在一条有向边,那么就是有三角关系。所以可以根据是否存在拓扑排序来判断是否有环,以及是否存在强连通分量(就是环)来判断。
代码:
tarjan求强连通
/*
在任何深度优先搜索中,
同一强连通分量内的所有顶点
均在同一棵深度优先搜索树中。
也就是说,强连通分量一定是有向图的某个深搜树子树。
即dfn[x]=low[x]
*/
#include<set>
#include<queue>
#include<vector>
#include<string>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 2000 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int n,m,x[N],y[N];
int head[N],len;
int dfn[N],low[N],dfs_num;//dfn表示遍历深度,low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int color[N],col_num,num[N];//染色
int stack[N],vis[N],top;//栈和栈指针
char map[N][N];
struct EdgeNode{
int from,to,next,w;
}edge[N*N];
void add(int i,int j){
edge[len].from=i;
edge[len].to=j;
//edge[len].w=w;
edge[len].next=head[i];
head[i]=len++;
}
void init(){
mem(vis,0),mem(dfn,0),mem(low,0),mem(head,-1),len=top=col_num=dfs_num=0;
}
void tarjan(int u){
dfn[u]=low[u]=++dfs_num;
vis[u]=1;//是否在栈中
stack[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]){
low[u]=min(dfn[v],low[u]);
}
}
if(dfn[u]==low[u]){//构成强连通分量
vis[u]=0;
//染色
color[u]=++col_num;
num[col_num]=1;
while(stack[top]!=u){//退栈
color[stack[top]]=col_num;
num[col_num]++;
vis[stack[top]]=0;
top--;
}
top--;
}
}
void solve(){
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
}
int main(){
int t,u,v,w,cas=0;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%s",map[i]+1);
for(int j=i+1;j<=n;j++){
if(map[i][j]=='1'){
add(i,j);
}
else{
add(j,i);
}
}
}
solve();
if(col_num<n){
printf("Case #%d: Yes\n",++cas);
}
else{
printf("Case #%d: No\n",++cas);
}
}
return 0;
}
拓扑排序:
#include<set>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 2000 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int n,m,len;
int head[N],indeg[N],ans[N];
char map[N][N];
struct node{
int to,w,next;
}edge[N*N];
void add(int i,int j){
indeg[j]++;
edge[len].to=j;
//edge[len].w=w;
edge[len].next=head[i];
head[i]=len++;
}
bool topo(){
mem(ans,0);
int cnt=1;
for(int i=1;i<=n;i++){
if(indeg[i]==0){
ans[cnt++]=i;
}
}
for(int i=1;i<=cnt;i++){
for(int k=head[ans[i]];k!=-1;k=edge[k].next){
indeg[edge[k].to]--;
if(indeg[edge[k].to]==0){
ans[cnt++]=edge[k].to;
}
}
}
if(cnt<n){
return 0;
}
else{
return 1;
}
}
void init(){
mem(head,-1),mem(edge,0),mem(indeg,0),len=1;
}
int main(){
int t,u,v,cas=0;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%s",map[i]+1);
for(int j=i+1;j<=n;j++){
if(map[i][j]=='1'){
add(i,j);
}
else{
add(j,i);
}
}
}
if(topo()){
printf("Case #%d: No\n",++cas);
}
else{
printf("Case #%d: Yes\n",++cas);
}
}
return 0;
}