当我们知道一组大小关系之后,可判断所有关系是否都能成立,即关系间没有矛盾。
例如: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;
}