POJ 1094 Sorting It All Out

题目大意:

        现有多个测例,每个测例都会给定一个序列长度n(2 ≤ n ≤ 26),序列有大写字母的前n个字母组成,接下来给定m个关系约束,每个关系由小于号规定,形式比如为"A < B",每读一个关系就要判断该序列是否能确定或者是否前后矛盾(比如前面的关系能推出A < B,后面的关系又能推出A > B),如果能确定出序列就要输出经过多少条关系后能确定出此序列,并且打印出该序列,如果推出前后矛盾,也要输出是经过多少条关系推出了前后矛盾这个结论,如果经过所有关系后也不能确定出该序列或者推出前后矛盾,就输出该序列无法确定的信息,输入的关系中的字母保证多处于前n个大写字母的范围,测例以n, m = 0表示结束。

题目链接

注释代码:

/*                               
 * Problem ID : POJ 1094 Sorting It All Out
 * Author     : Lirx.t.Una                               
 * Language   : C++                   
 * Run Time   : 16 ms                               
 * Run Memory : 180 KB                               
*/ 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

//序列最大长度
#define	MAXN	26

using namespace std;

char	deg[MAXN];//degree,入度
char	tmp_deg[MAXN];//临时空间,可以存放deg副本

bool	g[MAXN][MAXN];//graph,存放序列中各个元素之间的关系
char	fmt[4];//临时接受输入的字符串

queue<char>		ord;//存放最终确定下来的序列

int
topsort( int n, char *deg ) {//拓扑排序
	//n为序列的长度
	//deg,入度信息

	int		i;//计数变量
	int		u, v;//点
	bool	nosure;//标记序列是否是不确定的(就是拓扑排序会产生多种情况)

	queue<char>	que;//存放入度为0的点

	//上次排序可能不成功,有上次的信息留在ord中,需要清空不影响本次排序
	while ( !ord.empty() ) ord.pop();

	for ( i = 0; i < n; i++ )//找出所有入度为0的点存放到que中
		if ( !deg[i] ) que.push(i);

	nosure = false;//将不确定标记置为false
	while ( !que.empty() ) {
	
		//如果在去0入度点时有多个,就意味着拓扑排序的情况有多种
		if ( que.size() > 1 ) nosure = true;//将情况置为不确定
		//!!但是不确定并不意味着检查可以结束,因为可能会出现前后矛盾的情况
		//随着关系的增多不确定可能会转化为确定,但是一旦发现矛盾的情况就
		//应该立即对本次测例给出判断结论了

		ord.push((u = que.front()) + 'A');//暂且将该点放入ord中,如果最终不确定不输出就行了
		que.pop();

		for ( v = 0; v < n; v++ )//将所有与之相连的点的入度都-1,并且如果-1后为0就如队
			if ( g[u][v] && !(--deg[v]) )
				que.push(v);
	}

	//如果仍然有部分点入度不为0则表示有环,即出现了前后矛盾的情况
	if ( ord.size() < n ) return 'I';//比如A > B > C > A,这就矛盾了,并返回(I)nconsistency标记
	if ( nosure ) return 'N';//虽然不矛盾但是不确定(即有多种情况,序列不能唯一确定),返回(N)ot sure标记

	return 'D';//序列被唯一确定下来了,返回(D)etermained标记
}

int
main() {

	int		n, m;//序列长度,关系数
	int		u, v;//点
	int		stp;//表示经过多少步得出结论

	int		i;//计数变量

	bool	incn, detm;//inconsistency and determained,标记是否矛盾或者被唯一确定

	while ( scanf("%d%d", &n, &m), n ) {
		
		//初始化
		incn = false;
		detm = false;

		memset(g, false, sizeof(g));
		memset(deg, 0, sizeof(deg));

		for ( i = 1; i <= m; i++ ) {
		
			scanf("%s", fmt);

			if ( incn || detm ) continue;//如果两者中有一个被确定则不必再检查
			//虽然已经判断出来了但是也要把剩余的关系读完

			u = fmt[0] - 'A';//映射成数组下标
			v = fmt[2] - 'A';
			if ( g[v][u] ) {//如果存在反向边则可以直接判断出冲突
			
				incn = true;
				stp  = i;//记录关系数量
				continue;
			}
			if ( g[u][v] ) continue;//表示该关系重复输入

			//更新边和入度
			g[u][v] = true;
			deg[v]++;

			memcpy(tmp_deg, deg, sizeof(deg));
			switch ( topsort( n, tmp_deg ) ) {//拓扑排序
			
				case 'D' : 
					
					detm = true;
					stp  = i;
					break;

				case 'I' : 
					
					incn = true;
					stp  = i;
					break;

				default  : break;//未确定,还需等待下次关系输入后判断
			}
		}

		if ( detm ) {//关系都输完后得出结论
		
			printf("Sorted sequence determined after %d relations: ", stp);
			while ( !ord.empty() ) {
			
				putchar(ord.front());
				ord.pop();
			}
			puts(".");
		}
		else if ( incn )
			printf("Inconsistency found after %d relations.\n", stp);
		else//即不矛盾也没有确定,那就是没确定
			puts("Sorted sequence cannot be determined.");
	}

	return 0;
}
无注释代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

#define	MAXN	26

using namespace std;

char	deg[MAXN];
char	tmp_deg[MAXN];

bool	g[MAXN][MAXN];
char	fmt[4];

queue<char>		ord;

int
topsort( int n, char *deg ) {

	int		i;
	int		u, v;
	bool	nosure;

	queue<char>	que;

	while ( !ord.empty() ) ord.pop();

	for ( i = 0; i < n; i++ )
		if ( !deg[i] ) que.push(i);

	nosure = false;
	while ( !que.empty() ) {
	
		if ( que.size() > 1 ) nosure = true;

		ord.push((u = que.front()) + 'A');
		que.pop();

		for ( v = 0; v < n; v++ )
			if ( g[u][v] && !(--deg[v]) )
				que.push(v);
	}

	if ( ord.size() < n ) return 'I';
	if ( nosure ) return 'N';

	return 'D';
}

int
main() {

	int		n, m;
	int		u, v;
	int		stp;

	int		i;

	bool	incn, detm;

	while ( scanf("%d%d", &n, &m), n ) {
	
		incn = false;
		detm = false;

		memset(g, false, sizeof(g));
		memset(deg, 0, sizeof(deg));

		for ( i = 1; i <= m; i++ ) {
		
			scanf("%s", fmt);

			if ( incn || detm ) continue;

			u = fmt[0] - 'A';
			v = fmt[2] - 'A';
			if ( g[v][u] ) {
			
				incn = true;
				stp  = i;
				continue;
			}
			if ( g[u][v] ) continue;

			g[u][v] = true;
			deg[v]++;

			memcpy(tmp_deg, deg, sizeof(deg));
			switch ( topsort( n, tmp_deg ) ) {
			
				case 'D' : 
					
					detm = true;
					stp  = i;
					break;

				case 'I' : 
					
					incn = true;
					stp  = i;
					break;

				default  : break;
			}
		}

		if ( detm ) {
		
			printf("Sorted sequence determined after %d relations: ", stp);
			while ( !ord.empty() ) {
			
				putchar(ord.front());
				ord.pop();
			}
			puts(".");
		}
		else if ( incn )
			printf("Inconsistency found after %d relations.\n", stp);
		else
			puts("Sorted sequence cannot be determined.");
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值