POJ 1094 拓扑排序

2 篇文章 0 订阅
博客详细讨论了拓扑排序在POJ 1094问题中的应用,涵盖拓扑排序的三个方面:可行性、唯一性和输出。通过判断入度为0的节点数量来确定是否存在环,利用DFS检查唯一性。文章介绍了一种在添加边时完成判环并填充关系矩阵R的方法,当R矩阵除对角线外填满时,表示排序完成,并通过DFS输出拓扑序。
摘要由CSDN通过智能技术生成

这道题的确考查拓扑排序考查的挺全的

第一:是否可拓扑

第二:是否有唯一拓扑序

第三:输出拓扑序

是否可排序:当删点的时候度为0的点不是全部的点的时候,就一定出现了环

是否唯一:利用 dfs 判断一个图是否可以排序可以用删点的方法,当出现两个及以上 0 的入度的点的时候,便是不唯一

输出的话就排下序列然后输出就OK了..

只是我不是这么做的...

我之前只会 dfs 输出拓扑序,所以,判环这个任务就在加边的时候完成了

R[i][j] = 1 代表  i 比 j 大, -1 反之,0代表不缺定

每次加边的时候利用已经存在的关系递归的加下去。若出现冲突,则不能排序。若 R 数组中除 R[i][i] 之外都填满的时候,就完成了排序,DFS 一遍输出。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>

using namespace std;

int R[30][30];// R i to j 1 is big -1 is small
char s[50000][6];

int n,m;

bool OK()
{
	int m=n;
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(i==j)
				continue;
			if(R[i][j]==0)
				return false;
		}
	}
	return true;
}
vector<int> topo;
int used[30];
void dfs(int x)
{
	used[x]=1;
	for(int i=0;i<n;i++)
	{
		if(!used[i]&&R[x][i]==1)
			dfs(i);	
	}
	topo.push_back(x);
}
// a small b big
bool addR(int a,int b)
{
	if(R[a][b]==1)
		return false;
	if(R[a][b]==-1)
		return true;
	R[a][b]=-1;
	R[b][a]=1;
	int flag=true;
	for(int j=0;j<n;j++)
	{
		if(R[a][j]==1)
			flag&=addR(j,b);
		if(R[b][j]==-1)
			flag&=addR(a,j);
	}
	return flag;
}
int main()
{
	while(cin>>n>>m&&(n!=0||m!=0))
	{
		memset(R,0,sizeof(R));
		memset(used,0,sizeof(used));
		topo.clear();
		for(int i=0;i<m;i++)
			scanf("%s",s[i]);
		bool can=false;
		for(int i=0;i<m;i++)
		{
			int small=s[i][0]-'A';
			int big=s[i][2]-'A';
			if(!addR(small,big))
			{
				can=true;
				printf("Inconsistency found after %d relations.\n",i+1);
				break;
			}
			if(OK())
			{
				can=true;
				for(int j=0;j<n;j++)
					if(!used[j])
						dfs(j);
				char res[30];
				for(int j=0;j<n;j++)
					res[j]='A'+topo[j];
				res[n]='\0';
				printf("Sorted sequence determined after %d relations: %s.\n",i+1,res);
				break;
			}
		}
		if(!can)
			printf("Sorted sequence cannot be determined.\n");
	}	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值