hdu4324 Triangle LOVE 拓扑排序或强连通分量

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值