拓扑排序模板+题目

拓扑排序模板

输入初始化,记录有向边和入度

void Init(){
	for(int i=1;i<=m;i++){
		int t1,t2;
		scanf("%d%d",&t1,&t2);
		G[t1].push_back(t2);
		indegree[t2]++;
	}
}

拓扑排序函数

bool topo(){
	for(int i=1;i<=n;i++)
		if(!indegree[i])	q.push(i);    //如果要求字典序,就用优先队列
	int cnt = 0;
	while(!q.empty()){
		cnt++;
		int p = q.front();	q.pop();
		q2.push(p);
		for(int j=0;j<G[p].size();j++){
			int v = G[p][j];
			indegree[v]--;
			if(indegree[v] == 0)	q.push(v);
		}
	}
	if(cnt != n)	return false;   //用于判环
	else{
		while(!q2.empty())	cout<<q2.front()<<" ";	q2.pop();
	}
}

模板题:UVA10305&&HDU1285

hdu2647

题解:反向建边,初始度为0的不用给钱val = 0。每一个点的钱为上一个的加1。

代码:

#include <bits/stdc++.h>
using namespace std;
int const N = 10000 + 10;
int const LOW = 888;
int n,m,val[N];
vector<int>G[N];
int indegree[N];
int topo(){
	queue<int>q;
	for(int i=1;i<=n;i++)
		if(!indegree[i])	q.push(i);
	int cnt = 0;
	while(!q.empty()){
		cnt++;
		int p = q.front();	q.pop();
		for(int i=0;i<G[p].size();i++){
			int v = G[p][i];
			indegree[v]--;
			if(!indegree[v])	val[v] = val[p] + 1,	q.push(v);
		}
	}
	if(cnt != n)	return -1;
	int sum = 0;
	for(int i=1;i<=n;i++)
		sum += LOW + val[i];
	return sum;
}	
int main(){
	while(~scanf("%d%d",&n,&m)){
		for(int i=1;i<=n;i++)	G[i].clear(),	indegree[i] = 0,  val[i] = 0;
		for(int i=1;i<=m;i++){
			int t1,t2;
			scanf("%d%d",&t1,&t2);  //t1工资要比t2高
			G[t2].push_back(t1);    //反向建边
			indegree[t1]++;
		}
		printf("%d\n",topo());
	}
	return 0;
}

POJ1094

题解:这一题WA好多次。看来我对拓扑排序理解不够深刻。

  • 如果在循环当中,找到无法判断不要立刻返回,应该做好记录。因为有可能会出现矛盾。矛盾是第一要判断的。
  • 入度的数组要拷贝一份。我C语言基础没打好呀!orz。

代码:

#include <bits/stdc++.h>
using namespace std;
int const N = 30;
vector<int>G[N];
int n,m,in[N],tmp[N];
queue<int>q2;
int topo(int indegree[N]){
	queue<int>q;
	while(!q2.empty())	q2.pop();
	for(int i=1;i<=n;i++)
		if(indegree[i] == 0)	q.push(i);
	int cnt = 0;    
	bool flag = false;     //记录是否无法判断
	while(!q.empty()){
		if(q.size() > 1)	flag = true;
		cnt++;
		int p = q.front();	q.pop();
		q2.push(p);
		for(int i=0;i<G[p].size();i++){
			int v =G[p][i];
			indegree[v]--;
			if(indegree[v] == 0)	q.push(v);
		}
	}
	if(cnt != n)	return -1;//先判断是否矛盾
	if(flag)	return -2;    //再判断是否无法判断
	return 1;   //找到
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		if(!m && !n)	return 0;
		for(int i=1;i<=n;i++)	G[i].clear(),	in[i] = 0;
		int judge = 0;
		for(int i=0;i<m;i++){   //每读入一个关系进行以此拓扑排序
			char t,t1,t2;
			scanf(" %c %c %c",&t1,&t,&t2);	
			G[t1-'A'+1].push_back(t2-'A'+1);
			in[t2-'A'+1]++;
			memcpy(tmp,in,sizeof(in));    //拷贝一份
			if(!judge){
				int flag = topo(tmp);
				if(flag == 1){   //如果找到关系可能仅仅上A<B,B<C,但是后面还有C<D
					printf("Sorted sequence determined after %d relations: ",i+1);
						while(!q2.empty())	cout<<(char)(q2.front()+'A'-1),	q2.pop();
					printf(".\n");
					judge = 1;
				}else if(flag == -1){
					printf("Inconsistency found after %d relations.\n",i+1);
					judge = 1;
				}
			}
		}
		if(!judge)	printf("Sorted sequence cannot be determined.\n");
	}
}

HDU4857

题解:

代码:

#include <bits/stdc++.h>
using namespace std;
int const N = 30000 + 10;
int n,m,in[N],cnt;
int ans[N];
vector<int>G[N];
void topo(){
	priority_queue<int>q;
	cnt = 0;
	for(int i=1;i<=n;i++)
		if(!in[i])	q.push(i);
	while(!q.empty()){
		int p = q.top();	q.pop();
		ans[++cnt] = p;
		for(int i=0;i<G[p].size();i++)
			if(--in[G[p][i]] == 0)	q.push(G[p][i]);
	}
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)	G[i].clear();
		memset(in,0,sizeof(in));
		for(int i=1;i<=m;i++){    //有重复的边
			int a,b;	scanf("%d%d",&a,&b);
			G[b].push_back(a);	++in[a];
		}
		topo();
		printf("%d",ans[n]);
		for(int i=n-1;i>=1;i--)	printf(" %d",ans[i]);
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值