poj3687~拓扑排序(附上拓扑排序详解)_i++

题意非常坑爹,很多陷阱也很坑爹,要不是有Disscuss帮忙早就gg了。

题意:

给定N个球,这些球的编号分别是1-N中的某个数字,它们的重量也分别是1-N中的某个数字,任意两个球的编号和重量不相等。

给定一些类似a<b的约束,表示编号为a的球比编号为b的球轻。要求符合约束条件的各个球的重量。若答案有多种,则输出的答案必须让编号为1的球重量尽量轻,接着是编号为2的球重量尽量轻,一直到编号为N的球尽量轻。

注意:输出的是球1到球N的重量!也就是说讲1-N的重量分配到每个球,然后输出每个球的重量!


介绍一下拓扑排序:

算法思想:
  拓扑排序的算法:选一个入度为 0 的顶点输出,并将其所有后继顶点的入度—1,重复这两步直至输出所有顶点,或找不到入度为 0 的顶点为止,为便于查找入度为 0 的顶点,算法中利用顶点的入度域建立一个存放入度为 0 的顶点的栈。

具体变化过程看这个flash一目了然:http://www.tyut.edu.cn/kecheng1/site01/suanfayanshi/topological_sort.asp


陷阱:

*****要反向拓扑,例如3比2轻,那么入度加一的应该是3,然后拓扑的时候先从N开始循环,找到入度为0的求则赋上大的重量

比如4-->1,3-->2这个图,如果正向的话先出来的是3,然后是2,然后是4,最后才是1,是个反例,
而反向的话却可以保证把小的尽可能留给小标号的

*****注意判断重边

*****注意判断成环时的死循环



#include<iostream>
#include<string>
#include<stack>
#include<cmath>
#define M 210
using namespace std;

int in[M],map[M][M],ans[M],flag;

void topsort(int n)
{
int i,j,k=n;
while(k>=1)
{
for(i=n;i>=1;i--)
if(in[i]==0)
{
for(j=1;j<=n;j++) //与i相同的球,入度-1
if(map[i][j]==1)
in[j]--;
in[i]--; //自身也-1
ans[i]=k--; //赋值,附上大的那个
break;
}

if(i==0) {flag=0;break;} //如果陷入死循环,则退出
}
}

int main()
{
int t,n,m,i,a,b;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
memset(in,0,sizeof(in));
memset(map,0,sizeof(map));
flag=1;
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
if(a!=b) //防止相等
{
if(map[b][a]==0) //注意判断重边
{
map[b][a]=1;
in[a]++;
}
}
else flag=0;

}

if(flag)
{
topsort(n);

if(flag==0) //如果陷入死循环则输出-1
{
printf("-1\n");continue;
}

for(i=1;i<=n;i++)
printf("%d ",ans[i]);
cout<<endl;
}
else printf("-1\n");
}
}