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;
}
}
}
}
来源:https://www.cnblogs.com/lipoicyclic/p/12299954.html