CDOJ 1150 排名表 拓扑排序

http://www.acm.uestc.edu.cn/#/problem/show/1150
就是说有n个人,编号1-n,他们有一个排名表,然后已知m条信息,每条信息为a b,表示a在b前面
然后叫你写出一个满足这m个条件的排名表,
如果有多个的话,尽可能使1的名次最小,这个条件下,尽可能使2的名词最小,依次类推
然后从1-n输出 每个人的名次 (确实,被这个坑了一次,眼瞎

然后呢,给的解法是反向建图,然后拓扑排序,贪心,每次选编号最大的
呃,又是这种情况,就是我可以去理解这样为什么是对的,但是叫我想出来,可能不容易想出来,感觉还是应该多做多练吧
呃,为什么这样是对的呢,因为有这个限制条件:让编号为1的人的名次尽量小,然后让编号为2的人的名次尽量小,然后让编号为3的人的名次尽量小......
我们拓扑排序时,是选第一名是谁,第二名是谁,这样选的,所以,正向的话,我们可以实现,第一名的编号尽量小,然后第二名的编号尽量小,然后,,,
显然,这个条件和题目给的条件是不等价的
题目的条件,我们怎么理解呢,我们可以这样理解,尽量先选1,然后再尽量先选2,然后再尽量先选3,然后,,
这个不容易做啊,因为我们使1尽量先选,那就是找到1,然后,先把它给 排序了,就是,假如是3->4->1的话,就是3是第1名,4是第2名,1是第3名,然后这样选,选完1选2,,这样选,但是假如是3->4>1,7->2->1呢,我们发现,从1往回退时,还是每次选编号大的退,这样就使编号小的尽量靠前了,然后就跟下面的思路类似了
但是拓扑排序只能实现第i名的编号是尽量大还是尽量小,怎么办呢,
假如我们是反向建图,倒着选的话,就行先选最后一名,最后选第一名,那题目的限制条件就变为,尽量使1最后选,,然后尽量使2最后选,然后尽量使3最后选,我们发现,这就是说,我们尽量后选编号小的,编号越小我们越最后选,就是说,编号越大,我们越先选,所以就可以每次选编号大的,然后就可以了

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 202
#define maxm 202
bool graph[maxn][maxm];
int in[maxn];
int ans[maxn];
bool vis[maxn];
int main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	//ios::sync_with_stdio(false);
	//cin.tie(0); cout.tie(0);
	//ifstream in;
	//in.open("input.txt", ios::in);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		int a, b;
		memset(graph, 0, sizeof(graph));
		memset(in, 0, sizeof(int)*maxn);
		memset(ans, 0, sizeof(int)*maxn);
		memset(vis, 0, sizeof(vis));
		for (int i = 0; i < m; ++i)
		{
			scanf("%d%d", &a, &b);
			if (graph[b][a])
				continue;
			graph[b][a] = true;
			++in[a];
		}
		int cnt = n;
		while (1)
		{
			bool flag = true;
			for (int i = n; i >= 1; --i)
			{
				if (vis[i])
					continue;
				if (in[i] == 0)
				{
					flag = false;
					vis[i] = true;
					ans[i] = cnt--;
					for (int j = 1; j <= n; ++j)
					{
						if (graph[i][j])
						{
							graph[i][j] = 0;
							--in[j];
						}
					}
					break;
				}
			}
			if (flag)
				break;
		}
		if (cnt > 0)
			printf("-1\n");
		else
		{
			for (int i = 1; i <= n; ++i)
			{
				printf("%d", ans[i]);
				if (i == n)
					printf("\n");
				else
					printf(" ");
			}
		}
	}
	//while (1);
	return 0;
}

你可能感兴趣的:(图论,CDOJ)