POJ1094 Sorting It All Out
Input
Output
Sorted sequence determined after xxx relations: yyy...y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.
where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy...y is the sorted, ascending sequence.
Sample Input
4 6 A<B A<C B<C C<D B<D A<B 3 2 A<B B<A 26 1 A<Z 0 0
Sample OutputSorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations. Sorted sequence cannot be determined.
这是翻译过的题目https://www.acwing.com/problem/content/345/
首先要说的是题意描述不太对。如果在矛盾前能成功判断顺序则算成功,在这个前提下优先判断是否矛盾。
这个题的核心是利用Floyd算法构造传递闭包。以1~26代表A~Z。d[i][j]=1表示i对应的字母小于j对应的字母。构造完成后,若存在变量使得d[i][j]=1且d[j][i]=1说明矛盾,如果d[i][j]与d[j][i]有且仅有一个为1说明这条关系是成立的。d[i][j]与d[j][i]都为0的话要么是i或者j对应的字母输入里根本没涉及要么最终无法确定顺序。把所有出现过的字母列出来,按照出度(出边的数目)排序,出度最大的即为最小的字母变量。举个例子:1,2,3,4,5五个数,1小于2,3,4,5,因此出度为4;2小于3,4,5;因此出度为3…依次等差递减且出度和为n(n-1)/2。
因此可以确定整体思路:For循环每读取到一条关系,先把读取到的变量对应的数加入vector便于后续统计操作,在d数组里令d[a][b]=1(a为小的字母对应的数…),然后跑Floyd(代码在蓝书P360)。这里要注意的是:1.在Floyd里即可判断是否矛盾,如果矛盾直接return false。2.当跑Floyd时出度也会相应变化,因此要注意及时更新。
跑完后如果矛盾直接输出相应语句,吸收掉后面的输入并结束当前TestCase,没有矛盾的话检查当前给出所有关系涉及的字母是否等于n,不等于的话必然没法判断,直接continue,等于的话说明可以判断这些关系能不能确定最终的顺序。用一个结构体存变量对应的字母和出度,遍历vector,确定出度和,如果为(n-1)*n/2则能确定,把结构体按照出度从大到小排序(注意,最大的变量的出度和根本没涉及到的变量的出度都为0,直接排序不可,因此对于每个变量,如果在vector里能找到,则将其出度+1)。输出后吸收掉剩下的输入。如果不能确定的话根据矛盾与否输出对应的语句。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> using namespace std; int n,m; struct node { int num;//存字母编号 int out;//存出度 }; bool floyd(bool d[27][27],struct node nod[])//如果有矛盾 return false; { int i,j,k; for(k=1;k<=26;k++) { for(i=1;i<=26;i++) { for(j=1;j<=26;j++) { /////floyd也要更新出度 dp时出度会变化 d[i][j]|=d[i][k]&d[k][j]; if(i!=j&&d[i][j]==1&&d[j][i]==1)return false; } } } for(i=1;i<=26;i++)//更新出度 { int cnt=0; for(j=1;j<=26;j++) { if(d[i][j])cnt++; } nod[i].out=cnt; } return true; } bool cmp(node a,node b) { return a.out>b.out; } int main() { while(scanf("%d%d",&n,&m)&&n&&m) { int i; bool d[27][27]={0}; bool vis[27]={0}; int tot_vis=0;//涉及到的变量的个数 int contradict=0;//判断是否矛盾的变量 int sure=0; //判断能否确定顺序的变量 struct node nod[28];//方便输出排序 for(i=1;i<=26;i++) { nod[i].num=i; nod[i].out=0; } vector<int>v;//存储涉及到的变量 for(i=1;i<=m;i++) { char temp[5]; scanf("%s",temp); int a=temp[0]-'A'+1,b=temp[2]-'A'+1; if(!vis[a]) { vis[a]=1;tot_vis++;v.push_back(a); } if(!vis[b]) { vis[b]=1;tot_vis++;v.push_back(b); } d[a][b]=1;//传递的是小于关系 nod[a].out++;//出度++ //注意 在floyd时也要更新出度 bool pd=floyd(d,nod); if(!pd) { contradict=i; int z; for(z=i+1;z<=m;z++)//吸收剩下的 { char s[5]; scanf("%s",s); } break; } //当前这一遍如果没有矛盾 判断能否确定关系 if(tot_vis!=n)//字母都没出现全,肯定没法判断 { continue; } else { int q,w; int cnt=0; for(q=0;q<v.size();q++) { for(w=0;w<v.size();w++) { if(q!=w&&(d[v[q]][v[w]]==1&&d[v[w]][v[q]]==0))cnt++; } } if(cnt==v.size()*(v.size()-1)/2)//能确定 { sure=i;//标记确定 把sure变量赋值为第i次确定 int z; for(z=i+1;z<=m;z++)//吸收剩下的 { char s[5]; scanf("%s",s); } break; } else//不能确定 { continue; } } } if(sure)//能确定 { printf("Sorted sequence determined after %d relations: ",sure); int z; //输出序列 注意最后一个的出度为0 会和其他没出现过的字母混杂在一起 所以加一再排序 vector<int>::iterator it; for(z=1;z<=n;z++) { if((it=std::find(v.begin(),v.end(),nod[z].num))!=v.end())nod[z].out++; } sort(nod+1,nod+26+1,cmp); for(z=1;z<=n;z++)putchar('A'+nod[z].num-1); putchar('.');//不要忘记句点 cout<<endl; } else { if(contradict) { printf("Inconsistency found after %d relations.\n",contradict); } //if(contradict==0&&tot_vis!=n)//不矛盾且推断不出 else { cout<<"Sorted sequence cannot be determined."<<endl; } } } }