拓扑排序解决ABC比较大小问题

tech2025-10-11  5

拓扑排序解决ABC比较大小问题

ABC 有三个数,分别用A,B,C表示,告诉你他们的两两比较的结果,输出他们的大小关系。Input输入的数据有多组,每组数据有三行,每行有两个字母,表示前面的字母代表的数比后面的字母代表的数大,每行的两个字母不相同。Output如果他们比较的结果合法,那么把它们按照从小到大的顺序输出,两个字母中间应有“<”号,否则就输出“The input is not true!”,输出占一行。 Sample Input AB BC AC AB BA AC Sample Output C<B<A The input is not true!

既然是字母比较,那么拓扑排序就能很好解决这个问题。为什么? 因为拓扑排序是有向无环图,他的实质是对有向图的顶点排成一个线性序列。简单来说。由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

回到问题,我们需要的结果恰好就是一个序列,我们的输入可以看作是拓扑排序给定的先后顺序。且当成环时(AB BC CA),就会无法拓扑排序也就是ABC无法比较。

那么怎么排序呢? 首先我们需要处理输入的数据,就拿AB BC AC 举例子

AB相当于 A>B,由于我们的输出是从小到大 所以,姑且想象成B->A(此时A的入度需要+1,拓扑排序根据入度依次删除节点) 同时记录下B的可去的一个节点增加一个A

同理BC 就是B的入度+1,C的可去的一个节点增加一个B

最后AC 就是A的入度+1,C的可去的一个节点增加一个A

然后开始进行拓扑排序: 现在A的入度为2,B的入度为1,C的入度为0 找到C,删去它,并且找到它的可去的节点(C->A 和C->B)使A,B入度-1;

现在A的入度为1,B的入度为0,C已被处理 找到B,删去它,并且找到它的可去的节点(B->A)使A入度-1;

现在A的入度为0,B已被处理,C已被处理 找到A,删去它,发现他没有可去的节点,那么抵达末尾,循环结束;

因为有三个节点,所以如果我们循环三次说明是正确的。 然后按照删除节点的顺序打印C->B->A即可

以上便是

正常结果的情况

下面看看如果不是正确结果的情况

如果没有循环三次,说明他可能成环了,(AB BA AC) 经过上面同理处理,A入度为2,可去节点为B;B入度为1,可去节点为A; C入度为0可去节点为A 那么先删去C,然后使A入度-1,那么此时无入度为0的点跳出循环。

你可能会问若第三条不是AC而是BC呢?那会变成B的入度为2,然后先删C,B入度-1,还是没有入度为0的点。

接下来我们考虑一下特殊输入,比如AB出现两次,那么我们就需要让多余的数据不处理

还有就是一个节点指向两个节点,另外两个节点不知道顺序的情况(AB AB CB)B入度为0,但是AC入度均为1.所以没有入度为2的节点需要提前结束循环判为错误,因为我们的题目需要保证ABC存在绝对比较性

好了,下面是代码时间:

#include<iostream> #include<bits/stdc++.h> using namespace std; struct ABC{ char u;//自身所代表字母 int d;//入度 vector<int> v;//存比它大的字母 }e[3];//ABC分别对应三个点 queue<ABC> q; char res[4]; bool used(vector<int> v,int x)//判断vector是否存在x { for(vector<int>::iterator i=v.begin();i!=v.end();i++) { if(*i==x) { return true; } } return false; } int main() { int n=0; char x[3],y[3],z[3]; e[0].u='A'; e[1].u='B'; e[2].u='C'; //初始化ABC while(~scanf("%s%s%s",&x,&y,&z)) { e[x[1]-'A'].v.push_back(x[0]-'A'); e[x[0]-'A'].d++; if(!used(e[y[1]-'A'].v,y[0]-'A'))//如果没有加入到vector才加入,删去重复输入 { e[y[1]-'A'].v.push_back(y[0]-'A'); e[y[0]-'A'].d++; } if(!used(e[z[1]-'A'].v,z[0]-'A')) { e[z[1]-'A'].v.push_back(z[0]-'A'); e[z[0]-'A'].d++; } for(int i=0;i<3;i++)//获取入度为0的字母 { if(!e[i].d) { q.push(e[i]); break; } } int sum=0; while(!q.empty())//BFS { ABC temp=q.front(); res[sum++]=temp.u;//记录结果 q.pop(); if(temp.v.size()==2) { //如果某个点 和两个点连接 且那两个点的权值相等,说明两个点无法比较大小 if(e[temp.v[0]].d==e[temp.v[1]].d) break; } for(vector<int>::iterator i=temp.v.begin();i!=temp.v.end();i++) { if(!(--e[*i].d))//所连线边入度-1,且如果其入度为0,就加入队列 q.push(e[*i]); } } if(sum==3)//如果有三次则说明ok { cout<<res[0]<<"<"<<res[1]<<"<"<<res[2]<<endl; } else{ puts("The input is not true!"); } for(int i=0;i<3;i++)//重置e { e[i].d=0; e[i].v.clear(); } } }
最新回复(0)