本文主要是介绍poj 3687 Labeling Balls(拓扑排序),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
http://poj.org/problem?id=3687
非常坑的一道题,最后快要绕晕了。。
题意:有N个球,重量分别是1~N,给着n个球贴上标签。输入n,m代表n个球和m条边(a b),代表 标签为a的要比标签为b的轻。最后输出标签1~N对应的重量(注意是重量,而不是轻重关系),还有要注意“ you should output the one with the smallest weight for label 1, then with the smallest weight for label 2, then with the smallest weight for label 3 and so on... ”,意思是标签小的要尽可能贴在重量小的球上。
思路:因为标签小的要尽可能贴在重量小的球上,所以拓扑排序时要使标签小的尽可能的靠前。所以只是传统的拓扑排序每次取优先队列中入度为0并且数最小的不对的。因为即使该点最小,它后面连着的点未必是最小的。
例如上图,若先取入度为0且最小的话,是先取出3,而我们的目的是让标号小的尽量靠前,即应该让1尽量靠前,这与先取出3相违背,这时应该先取出6才能使1尽量靠前。对于2,8,2肯定先出队列。归纳起来便是对于若干平行的路径,小的头部不一定排在前面(如3),但大的尾部一定排在后面(如8).
1. 把所有出度为 0 的节点放进优先队列 PQ 2. WHILE: PQ 不是空队列 3. 从 PQ 中取出编号最大的元素 a,把 a 添加到答案的头部。 4. FOR:所有指向 a 的边 b → a 5. 把 b 的出度减 1。如果 b 的出度变为 0,则把 b 放进优先队列 PQ。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;int n,m;
int out[210];
int topo[210];
int map[210][210];
priority_queue < int, vector<int>,less<int> > que;int toposort()
{while(!que.empty()) que.pop();int cnt = 1;memset(topo,0,sizeof(topo));for(int i = 1; i <= n; i++)if(out[i] == 0)que.push(i);while(!que.empty()){int u = que.top(); //每次取出队列中最大的que.pop();topo[cnt++] = u; for(int i = 1; i <= n; i++){if(map[i][u] == 1){out[i]--;if(out[i] == 0)que.push(i);}}}if(cnt == n+1)return 1;return 0;}int main()
{int test;scanf("%d",&test);while(test--){scanf("%d %d",&n,&m);memset(out,0,sizeof(out));memset(map,0,sizeof(map));int flag = 1;for(int i = 0; i < m; i++){int a,b;scanf("%d %d",&a,&b);if(!map[a][b]){map[a][b] = 1;out[a]++;}if(a == b)flag = 0;}if(!flag){printf("-1\n");continue;}int tmp[210];int ans = toposort();if(ans == 0)printf("-1\n");else{for(int i = 1; i <= n; i++)tmp[ topo[i] ] = n+1-i; //编号,tmp[]存的是拓扑排序的逆序.for(int i = 1; i <= n-1; i++)printf("%d ",tmp[i]); //输出编号1~n对应的重量printf("%d\n",tmp[n]);}}return 0;
}
这篇关于poj 3687 Labeling Balls(拓扑排序)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!