【竞赛之路】(poj 1094) 变量排序

【问题描述】 
 
  把不同的变量进行升序排序用小于操作符命令实现的。例如由A < B, B < C 和 C < D 可以得到升序序列A, B, C, D 。

  在本题中,你将得到若干条小于操作符命令,形如 A < B 的格式,请你确定利用这些命令,能否得到一个唯一的升序序列。
    
  【输入格式】 
 
  第1行为整数n,m,n(2 <= n <= 26)表示参与排序的是前n个大写字母,m表示给出命令的条数。
    
  【输出格式】 
 
  输出一行:
  如果根据输入能得到唯一的升序序列,则输出“Sorted sequence determined after xxx relations: yyy...y. ”
  如果不能得到唯一的升序序列,则输出“Sorted sequence cannot be determined. ”
  如果不能得到升序序列,则输出“Inconsistency found after xxx relations. ”
  上面的信息中 xxx 是一个整数,是表示至多根据前xxx条信息就可以得出该结论。 yyy...y表示得到的升序序列的大写字母串。
    
  【输入样例】 
 
【样例1】
 4 6
 A < B
 A < C
 B < C
 C < D
 B < D
 A < B

【样例2】
 3 2
 A < B
 B < A

【样例3】
 26 1
 A < Z
    
  【输出样例】 
 
【样例1】
 Sorted sequence determined after 4 relations: ABCD.

【样例2】
 Inconsistency found after 2 relations.

【样例3】
 Sorted sequence cannot be determined.
    
  【数据范围】 
 
2 <= n <= 26

今天上课讲的第二题,开始做的时候还是有一点懵逼的,最先觉得要用传递闭包来解决的,但是,想了一下每次加条边都要O(n^3)这样的代价,呵呵。

但是本题的本质还是一个排序题,而且已知条件给出的是变量之间的大小关系(图的边),这不得不让人想到DAG图和拓补排序。

所以这个题的思路是:循环题目给出的信息,将每一个变量看作是DAG图的一个顶点,利用题目给出的大小关系,建立一个DAG图,并用BFS(或者DFS)对这个图进行拓补

排序,如果排序失败(也就是图有环,不是一个DAG)的话,显然就是第三种情况了,而排序成功的话,有两种情况:

1.有唯一的拓补序列;       2.拓补序列不唯一.

我们知道,拓补序列实质是一个满足DAG图的特殊的组合,所以要判断该组合是否唯一,就要看拓补排序中选择时选择个数是否唯一,所以只需在BFS时判断队列中是否

有两个以上的元素,如果有则说明是第二种情况(也就是排序过程中存在两种及以上种选择 因为在有多个元素时先选元素1和元素2都可以得到一个拓补序列,会使解不唯一)

否则则是情况1.

所以主算法框架为每读入一条信息进行一次排序,然后按照上面的规则判断并输出结果.

这个题有三个坑爹的地方,一个是不唯一情况的判定需要考察m个信息,因为信息少于m条时可能是无解的情况,但加上几条边又有解了.

第二是在判断终端节点时不能改变原来的出度入度数组

第三个是不能直接以(q.size()>1)就直接判断2,因为2是建立在有解的大前提下的,而q.size()>1时遍历到后面也可能无解

附上代码(刚刚手贱误删了望见谅)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=35;
vector<int>g[maxn];
int n,m;
int rd[maxn],trd[maxn];
char str[5];
vector<int>topo;
int BFS()
{
	queue<int>q;
	memcpy(trd,rd,sizeof(rd));
	topo.clear();
	
	for(int i=1;i<=n;i++)
	if(trd[i]==0)q.push(i);
	
	int flag=0;
	while(!q.empty())
	{
		if(q.size()>1)flag=2;
		int i=q.front();q.pop();
		topo.push_back(i);
		for(int k=0;k<g[i].size();k++)
		{
			int j=g[i][k];
			if(trd[j]>0)trd[j]--;
			if(trd[j]==0)q.push(j);
		}
	}
	
	if(topo.size()<n)return 0;
	
	if(flag==2)return 2;
	
	return 1;
	
}

int main()
{
	//freopen("my.in","r",stdin);
	//freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%s",str);
		int x,y;
		x=str[0]-'A'+1;
		y=str[2]-'A'+1;
		g[x].push_back(y);
		rd[y]++;
		int t=BFS();
		if(t==0)
		{
			printf("Inconsistency found after %d relations.",i);
			break;
		}
		else if(t==1)
		{
			printf("Sorted sequence determined after %d relations: ",i);
			for(int k=0;k<topo.size();k++)
			printf("%c",topo[k]+'A'-1);
			printf(".");
			break;
		}
		else if(i==m && t==2)
		{
			printf("Sorted sequence cannot be determined.");
			break;
		}
	}
	
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值