1416: 大小关系(拓扑排序)

当我们知道一组大小关系之后,可判断所有关系是否都能成立,即关系间没有矛盾。 
例如:A<B, A<C, B<C  通过这组关系我们可以得到A<B<C ,所有关系都成立,没有矛盾。 
 A<B, B<C, C<A  通过前两个关系我们得到 A<B<C ,这个关系与C<A矛盾,所有关系不能同时成立。 

现在我们知道m个关系,请判断这m个关系是否能成立,成立输出YES”,否则输出NO”。

输入

多组数据,每组数据如下:

第一行有两个字母m。 m代表m组关系(1<=m<=400),接下来m行每行有一个关系,用两个不同的字母和一个符号表示。(输入保证字母在A’-‘Z’之间,关系符号只有 > , <)

输出

对于每组数据输出YES”或NO”.

样例输入 Copy
3
A<B
A<C
B<C
3
A<B
B<C
C<A
样例输出 Copy
YES
NO

 思路:因为要拍先后顺序,所以使用拓扑排序,用结构体数组存每个字母的字符和比他大的字符的指针,相当于用邻接表存一个字符的所有大于他的字符,然后当op1<op2的时候,把op2插入以op1开头的邻接表的后面。

拓扑排序思路:枚举所有点,找到入度为0的点放入栈或队列中,当栈或队列不空的时候一直循环,取他的队头或栈顶,遍历以他为头节点的链表,遍历之后删除那个链(后面的数入度--),再判断一下如果入度变成0了就加入栈或队列中。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
struct name{
	char data;
	struct name *p;
};
int d[26];
int vis[26];
struct name ch[26];
void in(){//初始化
	for(int i=0;i<26;i++){
		ch[i].data =(char)(i+65);//记录他的符号
		ch[i].p =NULL;//记录大于他的字符的指针
	}
}
bool tomp(struct name ch[],int n){
	stack<int> s;
	for(int i=0;i<26;i++){
		if(vis[i]!=0&&d[i]==0){//当他被输入过而且入度为0的时候加入栈
			s.push(i); 
		}
	}
	int con=0;//记录放到栈中的数的个数
	while(s.size() ){//当他不空
		int tt=s.top() ;//取栈顶
		con++;//更新个数
		s.pop() ;
		struct name *q;
		for(q=ch[tt].p ;q;q=q->p ){//遍历以栈顶元素为下标的元素的后面的元素
			char kk=q->data ;
			d[kk-65]--;//遍历到的字符的入度--
			if(d[kk-65]==0){//如果入度是0就加入到栈中
				s.push(kk-65); 
			}
		}
	}
	return con==n;//最后判断栈中的个数是不是加了n个,如果是就说明有拓扑序
}
int main(){
	int m;
	while(scanf("%d",&m)!=EOF){
		in();
		memset(d,0,sizeof d);
		memset(vis,0,sizeof vis);
		char op[5];
		int num=0;*//记录不同字符的种数
		while(m--){
			scanf("%s",op);
			if(vis[op[0]-65]==0){//如果他没有被记录过
				vis[op[0]-65]=1;//记录
				num++;//种数++
			}
			if(vis[op[2]-65]==0){
				vis[op[2]-65]=1;
				num++;
			}
			if(op[1]=='<'){//如果是小于就把后面的字符插入以前面字符为头节点的链表中
				struct name *q;
				q=(struct name*)malloc(sizeof(name));//记得动态申请内存
				q->data =op[2];
				q->p =ch[op[0]-65].p ;
				ch[op[0]-65].p =q;
				d[op[2]-65]++;
			}else{
				struct name *q;
				q=(struct name*)malloc(sizeof(name));
				q->data =op[0];
				q->p =ch[op[2]-65].p ;
				ch[op[2]-65].p =q;
				d[op[0]-65]++;
				
			}
			
		}if(tomp(ch,num)){
				printf("YES\n");
			}else printf("NO\n");
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值