HDU6165(tarjan算法 强连通缩点,拓扑排序)

这里说明一下,tarjan是一个人,他发明的算法都以他命名,所以,tarjan后面要加后缀,不然不知道是哪个算法。

一道比较标准的模板题,这里有篇很好的讲强 tarjan求强连通分量 的博客点击打开链接

我这里直接把新图构建出来了,然后拓扑排序即可,只要那一层出现两个入度为0的点即不能到达。

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int T,n,m;
int sccn,dfni;
int scc[1005],dfn[1005],low[1005];
vector<int> mp[1005],newmp[1005];
stack<int> stac;
int instac[1005];

void init() {
	sccn=0;
	dfni=1;
	memset(low,0,sizeof(low));
	memset(scc,0,sizeof(scc));
	memset(instac,0,sizeof(instac));
	memset(dfn,0,sizeof(dfn));
	for(int i=1;i<=n;i++) {
		mp[i].clear();
	} 
}

void tarjan(int p) {
	dfn[p]=low[p]=dfni;
	dfni++;
	instac[p]=1;
	stac.push(p);
	for(int i=0;i<mp[p].size();i++) {
		int v=mp[p][i];
		if(dfn[v]==0) {
			tarjan(v);
			if(low[v]<low[p])
			    low[p]=low[v];
		}else if(instac[v]&&dfn[v]<low[p]) {
			low[p]=dfn[v];
		}
	}
	if(dfn[p]==low[p]) {
		sccn++;
		int te=0;
		while(te!=p) {
			te=stac.top();
			scc[te]=sccn;
			instac[te]=0;
			stac.pop();
		}
	}
}

bool visit[1005][1005];//新图以scc为单位 
void newmap() {
	memset(visit,0,sizeof(visit));
	for(int i=1;i<=sccn;i++) {
		newmp[i].clear();
	}
	for(int i=1;i<=n;i++) {
		for(int j=0;j<mp[i].size();j++) {
			if(scc[i]!=scc[mp[i][j]]&&visit[scc[i]][scc[mp[i][j]]]==0) {
				newmp[scc[i]].push_back(scc[mp[i][j]]);
				visit[scc[i]][scc[mp[i][j]]]=1;
			} 
		}
	}
}

int degree[1005],pi,pnum;
int toposort() {
	memset(degree,0,sizeof(degree));
	for(int i=1;i<=sccn;i++) {
		for(int j=0;j<newmp[i].size();j++) {
		    degree[newmp[i][j]]++;
		}
	}
	while(1) {
		pi=0,pnum=0;
		for(int i=1;i<=sccn;i++) {
			if(degree[i]==0) {
				pnum++;
				pi=i;
			}
	    }
	    if(pnum==0) {
	    	return 1;
		}else if(pnum>=2) {
			return 0;
		}else if(pnum==1) {
			degree[pi]=-1;
			for(int i=0;i<newmp[pi].size();i++) {
				degree[newmp[pi][i]]--;
			}	
		}
	}
	return 1;	
}

int main() {
	//freopen("fuck.txt","r",stdin);
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		init();
		for(int i=1;i<=m;i++) {
			int u,v;
			scanf("%d%d",&u,&v);
			mp[u].push_back(v);
		}
		for(int i=1;i<=n;i++) {
			if(scc[i]==0) {
				tarjan(i);
			}
		}
		newmap();
		if(toposort()) {
			printf("I love you my love and our love save us!\n");
		}else {
			printf("Light my fire!\n");
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值