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. Swift - 类和结构体的区别

    类和结构体有许多相同之处,也有许多不同之处. 二者区别如下: 1,类可以继承和扩展,结构体不可以 2,可以让一个类的实例来反初始化,释放存储空间,结构体做不到 3,类的对象是引用类型,而结构体是值类型 ...

  2. 带着项目学PHP第九讲 - 如何给ecshop的wap版本首页和商品页添加商品图片

    ecshop的wap版本自身不带图片, 所以看起来光秃秃的,非常不讨人喜欢, 网络上关于wap的模板就不像pc版那么多,容易找到, 而且能找到的都是要花钱买的, 虽然这个小小的改动不能替代找个合适的模 ...

  3. maven项目配置Project Facets时further configuration available不出来问题

    如果下边的 further configuration available不出来 把Dynamic web module 去掉勾选,应用与项目,然后再点开项目的properties,再选中Dynami ...

  4. CentOS6.5与window远程桌面配置

    VNC配置手冊 一.服务端 VNC(Virtual Network Computing)是一种Linux系统(或者BSD.Mac等)下经常使用的图形化远程管理工具.使用的是RFB协议.VNC跟SSH一 ...

  5. 利用手工编码的方式对srtus2进行输入验证

    对action方法进行校验有两种方法一种是: 1手工编码书写 2一种是用xml 输入校验的流程: 1类型转化器对请求参数执行类型转化,并把转换后的值赋给action属性. 2.如果执行类型转化的过程中 ...

  6. 开发腾讯移动游戏平台SDK Android版Ane扩展 总结

    本文记录了在开发 腾讯移动游戏平台SDK(MSDK) Android版Ane扩展 过程中所遇到的问题和相关解决方式 问题一:编译报错:Unable to resolve target 'android ...

  7. adnroid仿miui的dialog

    先来看下效果图: 当中show和dismiss的时候有动画效果. 原先试过使用PopupWindow来做,可是使用的时候不是那么舒服,毕竟不是dialog嘛. 所以这次尝试还是使用dialog来做 , ...

  8. Spark实践的阶段性总结

    写这篇小总结是因为前段时间是自己业余时间对Spark相关进行了些探索,接下来可能有别的同事一起加入,且会去借用一些别的服务器资源,希望可以借此理下思路. 实践Spark的原因 在之前Spark简介及安 ...

  9. 7.MongoDB java CRUD

    注意:要增加mongodb对应的jar包 package cn.toto.mongodb; import java.net.UnknownHostException; import org.bson. ...

  10. webapi Task

    webapi+Task并行请求不同接口实例 标题的名称定义不知道是否准确,不过我想表达的意思就是使用Task特性来同时请求多个不同的接口,然后合并数据:我想这种场景的开发对于对接过其他公司接口的人不会 ...