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

《poj3687~拓扑排序(附上拓扑排序详解)》

题意非常坑爹,很多陷阱也很坑爹,要不是有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");
	}
}

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/a799581229/article/details/38961223
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞