Labeling Balls
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10161   Accepted: 2810

Description

Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 toN in such a way that:

  1. No two balls share the same label.
  2. The labeling satisfies several constrains like "The ball labeled with a is lighter than the one labeled withb".

Can you help windy to find a solution?

Input

The first line of input is the number of test case. The first line of each test case contains two integers,N (1 ≤
N ≤ 200) and M (0 ≤ M ≤ 40,000). The nextM line each contain two integers
a and b indicating the ball labeled witha must be lighter than the one labeled with
b. (1 ≤ a, bN) There is a blank line before each test case.

Output

For each test case output on a single line the balls' weights from label 1 to labelN. If several solutions exist, 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... If no solution exists, output -1 instead.

Sample Input

5

4 0

4 1
1 1 4 2
1 2
2 1 4 1
2 1 4 1
3 2

Sample Output

1 2 3 4
-1
-1
2 1 3 4
1 3 2 4

Source



解题思路:

每做一道题都能够学到新的思路。

由编号1—N的N个小球,重量也为1—N(easy混淆),给出一些限制条件,a  b,代表着编号为a的小球比编号为b的小球的重量小。依据限制条件。给小球分配重量,最后输出的是编号1—N的小球的重量。假设有多种方法,那么编号小的小球重量尽量小。

拓扑排序有多种写法,能够用栈,能够用队列,也能够用循环,不同的情况下用不同的方法。如本题就能够用循环。外层循环也代表着须要分配的重量。

这个题不能用正向建边,拓扑排序。。没想到这一点。。由于要求编号小的小球重量尽量小,在正向拓扑排序有多种方法的时候,不能保证这一点。做法为逆向建边,每次找入度为0的编号,重量从大到小进行赋值。最后还要提一点,大数据还得用scanf,时间差距太大了。。

以下两篇博文的解释我认为不错:

http://www.cnblogs.com/rainydays/archive/2011/07/20/2112047.html

分析:拓扑排序,注意依据题的要求,要先保证1号球最轻,假设我们由轻的向重的连边,然后我们依次有小到大每次把重量分给一个入度为0的点,那么在拓扑时我们面对多个入度为0的点。我们不知道该把最轻的分给谁才干以最快的速度找到1号(使1号入度为0),并把当前最轻的分给1号。所以我们要由重的向轻的连边,然后从大到小每次把一个重量分给一个入度为0的点。

这样我们就不用急于探求最小号。我们仅仅须要一直给最大号附最大值,尽量不给小号赋值,这样自然而然就会把轻的重量留给小号。(转)

http://blog.163.com/xiaohuang_17/blog/static/5458538620099874334826/(转载)

id=3687" style="text-decoration:none; color:rgb(206,0,1)">PKU 3687 在主要的拓扑排序的基础上又添加了一个要求:编号最小的节点要尽量排在前面;在满足上一个条件的基础上,编号第二小的节点要尽量排在前面。在满足前两个条件的基础上,编号第三小的节点要尽量排在前面……依此类推。

(注意。这和字典序是两回事,不能够混淆。)



    如图 1 所看到的。满足要求的拓扑序应该是:6 4 1 3 9 2 5 7 8 0。





图 1 一个拓扑排序的样例

一般来说,在一个有向无环图中,用 BFS 进行拓扑排序是比較常见的做法,如算法 1 所看到的。可是它不一定能得到本题要求的拓扑序。

1. 把全部入度为 0 的节点放进队列 Q
2. WHILE: Q 不是空队列
3.     从 Q 中取出队列首元素 a。把 a 加入到答案的尾部
4.     FOR:全部从 a 出发的边 a → b
5.         把 b 的入度减 1。假设 b 的入度变为 0。则把 b 放进队列 Q。


算法 1 用 BFS 进行拓扑排序

为了解决本问题。以下让我来探究一下拓扑序的一些性质。

图 1 为例。节点 0 毫无疑问排在最后。除了节点 0 以外,有三条互相平行的路径:6 → 4 → 1、 3 → 9 → 2 和 5 → 7 → 8。一条路径上的各个节点的先后关系都是不能改变的。比方路径 6 → 4 → 1 上的三个节点在拓扑序中。一定是 6 在最前,1在最后。

可是,互相平行的各条路径,在总的拓扑序中随意交错都是合法的。比方。以下都是
1
 的合法拓扑序:



    6 4 1 3 9 2 5 7 8 0、 3 6 9 4 5 1 7 8 2 0、 5 6 4 7 3 8 1 9 2 0、 3 5 6 4 1 7 9 2 8 0、 6 5 7 8 4 3 9 21 0。



    怎么才干找出题目要求的拓扑序呢?在这里。我想用字典序最先的拓扑序来引出这个算法。

算法 2 能够求出字典序最先的拓扑序。

1. 把全部入度为 0 的节点放进优先队列 PQ
2. WHILE: PQ 不是空队列
3. 从 PQ 中取出编号最小的元素 a,把 a 加入到答案的尾部
4. FOR:全部从 a 出发的边 a → b
5. 把 b 的入度减 1。假设 b 的入度变为 0,则把 b 放进优先队列 PQ。


算法 2 求出字典序最先的拓扑序

可见,算法 2 和算法
1
 基本一样。仅仅是把队列改成了优先队列。用它求出的图 1 的字典序最先的拓扑序为:3 5 6 4 1 7 8 9 2 0。

可是这显然不是本题要求的答案,由于节点
1 的位置还不够靠前。

算法 2 能够算是一个贪心算法,每一步都找编号最小的节点。可是对于
1
 中的三条路径。头的编号比較小的,不一定要先出队列。正确的步骤应该例如以下:

  1. 节点 0 的位置是铁定在最后的,不用考虑。

    仅仅考虑剩下的三条路径。

  2. 先找编号最小的,节点 1。

    把它和它所在的路径中位于它前面的节点所有拿出来。眼下的答案是 64 1。这样, 节点 1 就尽量靠前了。

  3. 再找剩下的节点中编号最小的,节点 2。把它和它所在的路径中位于它前面的节点所有拿出来。

    眼下的答案是 6 4 1 3 9 2 ,这样。节点
    2 就尽量靠前了。

  4. 仅仅剩下一条路径了,仅仅能依次把当中的节点拿出来。最后答案就是 6 4 1 3 9 2 5 7 8 0。

显然。算法 2 的贪心策略对于这个问题是不可行的。不能着眼于每条路径的头,而是要找编号最小的节点在哪条路径上。优先把这条路径拿出来。但问题在于。在
BFS 的过程中。我们仅仅能看到每条路径的头,看不到后面的节点,这该怎么办呢?



    让我们换个角度想一想,节点 3 和 6,应该是 6 先出队列,由于节点 1 在 6 的后面。这和节点 3 和 6 的编号大小没有不论什么关系。可是,再看另外两条路径的尾部。节点 2 和 8,能够肯定地说。2 一定先出队列,由于它们后面都没有别的节点了,这个时候全然以这两个节点本身的编号大小决定顺序。归纳起来就是说,对于若干条平行的路径,小的头部不一定排在前面。可是大的尾部一定排在后面。于是,就有了算法
3

1. 把全部出度为 0 的节点放进优先队列 PQ
2. WHILE: PQ 不是空队列
3. 从 PQ 中取出编号最大的元素 a,把 a 加入到答案的头部。 4.     FOR:全部指向 a 的边 b → a
5.     把 b 的出度减 1。假设 b 的出度变为 0,则把 b 放进优先队列 PQ。


算法 3 求出本题目要求的拓扑序

代码:
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std;
const int maxn=210;
int graph[maxn][maxn];
int indegree[maxn];
int output[maxn];
int n,m;
bool ok;//推断能否够。 void topo()
{
for(int i=n;i>=1;i--)
{
int MinNum=-1;
for(int j=n;j>=1;j--)//找入度为0的编号,这里是编号最大的入度为0的点,和用优先队列效果是一样的。 if(!indegree[j])
{
MinNum=j;
indegree[j]--;//别忘了这一句
break;
}
if(MinNum==-1)//找不到入度为0的点,说明有环
{
ok=0;
return ;
} output[MinNum]=i;//重量i分给编号为MinNum的球 for(int j=1;j<=n;j++)
if(graph[MinNum][j])
indegree[j]--;//与编号为0的点相连的点入度--
}
} int main()
{
int t;cin>>t;
int a,b;
while(t--)
{
memset(indegree,0,sizeof(indegree));
memset(graph,0,sizeof(graph));
ok=1;
scanf("%d%d",&n,&m);
if(ok==0)
continue;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(graph[a][b])//有逆向边
{
ok=0;
continue;
} if(!graph[b][a])//逆向建边
{
graph[b][a]=1;
indegree[a]++;
}
}
topo();
if(ok)
{
for(int i=1;i<n;i++)
printf("%d ",output[i]);
printf("%d\n",output[n]);
}
else
printf("-1\n");
}
return 0;
}

附上邻接表的做法:

有时候邻接矩阵数组开不出来仅仅能用邻接表来做
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
const int maxn=30010;
vector<int>adj[maxn];
int indegree[maxn];
int output[maxn];
int n,m;
bool ok; void topo()
{
for(int i=n;i>=1;i--)
{
int MinNum=-1;
for(int j=n;j>=1;j--)
if(!indegree[j])
{
MinNum=j;
indegree[j]--;
break;
}
if(MinNum==-1)
{
ok=0;
return ;
}
output[MinNum]=i;
for(int j=0;j<adj[MinNum].size();j++)
indegree[adj[MinNum][j]]--;
}
} int main()
{
int t;cin>>t;
int a,b;
while(t--)
{
memset(indegree,0,sizeof(indegree));
ok=1;
scanf("%d%d",&n,&m);
if(ok==0)
continue;
for(int i=1;i<=n;i++)
adj[i].clear();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
adj[b].push_back(a);
indegree[a]++;
}
topo();
if(ok)
{
for(int i=1;i<n;i++)
printf("%d ",output[i]);
printf("%d\n",output[n]);
}
else
printf("-1\n");
}
return 0;
}





[ACM] POJ 3687 Labeling Balls (拓扑排序,反向生成端)的更多相关文章

  1. poj 3687 Labeling Balls(拓扑排序)

    题目:http://poj.org/problem?id=3687题意:n个重量为1~n的球,给定一些编号间的重量比较关系,现在给每个球编号,在符合条件的前提下使得编号小的球重量小.(先保证1号球最轻 ...

  2. PKU 3687 Labeling Balls(拓扑排序)

    题目大意:原题链接 给出N个未编号的质量各不相同的球,以及它们质量轻重的大小关系,给它们从1-N贴标签编号,无重复.问是否存在可行的编号方法,不存在输出-1, 如果存在则输出唯一一种方案,此方案是使得 ...

  3. poj 3687 Labeling Balls - 贪心 - 拓扑排序

    Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N ...

  4. POJ 3687 Labeling Balls(反向拓扑+贪心思想!!!非常棒的一道题)

    Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16100   Accepted: 4726 D ...

  5. poj 3687 Labeling Balls【反向拓扑】

    Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12246   Accepted: 3508 D ...

  6. POJ 3687 Labeling Balls【拓扑排序 优先队列】

    题意:给出n个人,m个轻重关系,求满足给出的轻重关系的并且满足编号小的尽量在前面的序列 因为输入的是a比b重,但是我们要找的是更轻的,所以需要逆向建图 逆向建图参看的这一篇http://blog.cs ...

  7. poj 3687 Labeling Balls(拓补排序)

    Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them ...

  8. POJ 3687 Labeling Balls (top 排序)

    Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15792   Accepted: 4630 D ...

  9. POJ - 3687 Labeling Balls (拓扑)

    (点击此处查看原题) 题意 此处有n盏灯,编号为1~n,每盏灯的亮度都是唯一的,且在1~n范围之间,现已知m对灯之间的关系:a b ,说明灯a的亮度比灯b小,求出每盏灯的亮度,要求字典序最小(编号小的 ...

随机推荐

  1. [iOS]简单的APP引导页的实现 (Swift)

    在第一次打开APP或者APP更新后通常用引导页来展示产品特性 我们用NSUserDefaults类来判断程序是不是第一次启动或是否更新,在AppDelegate.swift中加入以下代码: func ...

  2. Oracle ACL(Access Control List)

    在oralce 11g中假如你想获取server的ip或者hostname,执行如下语句 SELECT utl_inaddr.get_host_address FROM dual;  //获取IP S ...

  3. PAIP: Paradigms of Artificial Intelligence Programming

    PAIP: Paradigms of Artificial Intelligence Programming PAIP: Paradigms of Artificial Intelligence Pr ...

  4. Python使用heapq实现小顶堆(TopK大)、大顶堆(BtmK小)

    Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) | 四号程序员 Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) 4 Replies 需1求:给出N长 ...

  5. IE 兼容模式

    兼容模式的由来 早期的浏览器, IE 独大.这也就导致其很多东西和w3c 的标准有很多不一样的地方.譬如他有自己才看的懂得自定义Tag. 一个熟悉的名词--浏览器大战, 形象的刻画了这期间发生的事情. ...

  6. LeetCode——Search in Rotated Sorted Array II

    Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this ...

  7. ssh, maven and eclipse 那些破事

    Unix根据该理念keep it simple, keep it stupid.可在j2ee有keep it complex, keep it smart. 所以,我彻底晕菜. 最后能活着把sprin ...

  8. mongodb中的排序和索引快速学习

    在mongodb中,排序和索引其实都是十分容易的,先来小结下排序: 1 先插入些数据    db.SortTest.insert( { name : "Denis", age : ...

  9. NEU月赛Segment Balls(线段树)

    问题 D: Segment Balls 时间限制: 1 Sec  内存限制: 128 MB 提交: 253  解决: 37 题目描述 Small K has recently earn money i ...

  10. 获取webshell的十种方法

    黑客在入侵企业网站时,通常要通过各种方式获取webshell从而获得企业网站的控制权,然后方便进行之后的入侵行为.本篇文章将如何获取webshell总结成为了十种方法,希望广大的企业网络管理员能够通过 ...