题解 P1347 【排序】
mydiplomacy · · 题解
这一道较为简单的拓扑排序题WA了3次才AC,我的思路跟大多数题解不同,发题解记录一下QwQ
我们将每个字母转化为一个点,只需要考虑整个图拓扑排序的情况。
这道题需要判断矛盾、得不到解的情况。
首先,如果这道题目改为:给出X条限制,判断这
bfs版的拓扑排序是:首先将
for i in range[1,n] :
i入队
while 队列不为空 :
取队首u
for u发出的边p :
du[p->v]--;
//p所指向的点的入度--,也相当于把u发出的边都删去
if du[p->v]==0 :
p->v入队
首先,这样拓扑排序的结果是什么?
由于符合条件的点就入队,所以最终队列里的点的顺序就是拓扑排序中的队列所存的结果。
接下来考虑如何判断是否矛盾。
当没有入度为零的点的时候,显然条件有矛盾。 同时,当出现矛盾时,有些点的入度永远不会减到零,这就意味着这些点永远入不了队。
因此,当没有点入度为零,或当最终入队的点的个数<n的时候,条件有矛盾。
最后,我们考虑怎样判断条件不足。
如果最开始入度为零的点有不止一个,那么条件一定不足,因为这两个点的顺序无法确定。 同时,如果每次取队首时,有不止一个点入队了,那么条件一定不足,因为这两个点都只有队首连向的边。所以这两个点无法确定顺序。
另外就是,如果同时满足条件矛盾与条件不足,这时应该判定为条件矛盾。大家可以思考一下为什么(我就是因为这个WA的QwQ)
因此,当有不止一个点入度为零,或当取同一个队首u时有不止一个v的入度变成了零,则条件不足。
这道题数据范围比较小,所以只需要遍历每个
附代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=30,maxm=905;
struct Node
{
int v;
Node *next;
}*h[maxn],pool[maxm];
int tot;
int du[maxn];
int q[maxn],head,tail;
int n,m;
void addEdge(int u, int v)
{
Node *p=&pool[++tot];
p->v=v; p->next=h[u]; h[u]=p;
}
int toposort() //返回值为1代表成立,返回值为0代表条件不足,返回值为-1代表条件矛盾
{
int temp=0;
int f=0;
for(int i=1;i<=n;i++)
{
if(du[i]==0)
{
q[tail++]=i;
temp++;
}
}
if(temp>1)
f=1;
while(head<tail)
{
temp=0;
int u=q[head++];
for(Node *p=h[u];p;p=p->next)
{
du[p->v]--;
if(du[p->v]==0)
{
q[tail++]=p->v;
temp++;
}
}
if(temp>1)
f=1;
}
if(tail!=n)
return -1;
else
if(f==1)
return 0;
else return 1;
}
struct Edge
{
int u,v;
}a[maxm];
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
char aa,bb,cc;
cin>>aa>>bb>>cc;
a[i].u=aa-'A'+1; a[i].v=cc-'A'+1;
}
for(int i=1;i<=m;i++)
{
addEdge(a[i].u,a[i].v);
head = tail = 0;
memset(du,0,sizeof(du));
for(int j=1;j<=i;j++) du[a[j].v]++;
int flag=toposort();
if(flag==1)
{
cout<<"Sorted sequence determined after "<<i<<" relations: ";
for(int j=0;j<=n-1;j++)
{
cout<<(char)(q[j]+'A'-1);
}
cout<<'.'<<endl;
return 0;
}
else if(flag==0) continue;
else
{
cout<<"Inconsistency found after ";
cout<<i<<" relations."<<endl;
return 0;
}
}
cout<<"Sorted sequence cannot be determined."<<endl;
return 0;
}