题目是要给n个重量1到n的球编号,有一些约束条件:编号A的球重量要小于编号B的重量,最后就是要输出字典序最小的从1到n各个编号的球的重量。

正向拓扑排序,取最小编号给最小编号是不行的,不举出个例子真的很难理解= =比如这个数据:

1

4 2

4 1

3 2

正确答案是2 4 3 1,会得到的错误答案是4 2 1 3。

一开始我是用了贪心的做法,每次选未安排重量的最小的编号,安排给它尽量小的重量。某个编号能得到的最小的重量的计算是这样的:

  • 计算出约束中重量要小于此编号的编号个数,记为k,这个可以先用Floyd预处理出任意两点间的连通性然后遍历一遍统计
  • 因而这个编号能得到的最小重量就是第k个还没被用的重量
  • 这时候还要回溯把所有约束中重量要小于到这个编号的编号给他们安排上k-1个重量

见代码:

 #include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
bool map[][];
int n,m;
bool floyd(){
for(int k=; k<=n; ++k){
for(int i=; i<=n; ++i){
for(int j=; j<=n; ++j){
map[i][j]|=(map[i][k]&map[k][j]);
}
}
}
for(int i=; i<=n; ++i) if(map[i][i]) return ;
return ;
}
bool vis[];
int getk(int k){
for(int i=; i<=n; ++i){
if(!vis[i]) if(--k==) return i;
}
return ;
}
int d[];
void dfs(int u){
if(d[u]) return;
int cnt=;
for(int v=; v<=n; ++v){
if(map[v][u] && !d[v]) ++cnt;
}
d[u]=getk(cnt+);
vis[d[u]]=;
for(int v=; v<=n ;++v){
if(map[v][u]) dfs(v);
}
}
int main(){
int t,a,b;
scanf("%d",&t);
while(t--){
memset(d,,sizeof(d));
memset(map,,sizeof(map));
memset(vis,,sizeof(vis));
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&a,&b);
map[a][b]=;
}
if(!floyd()){
puts("-1");
continue;
}
for(int i=; i<=n; ++i){
dfs(i);
printf("%d ",d[i]);
}
putchar('\n');
}
return ;
}

事实上这题正解是反着进行拓扑排序,就是逆图中进行拓扑排序,取最大编号给最大重量。

正确性我是这么理解的:

当前安排的编号是x,有两个入度0的结点a和b,且a<b,按算法是给b球编号x。

反证法,假设给a球编号x能更优,那么

Case b: ...[ ]...[ ]...[x] [ ]... (weight[b]=x)

Case a: ...[y]...[x]...[ ] [ ]... (weight[a]=x)

在后面编号的安排中,就存在一个小于x的编号y被安排在了(Case a)中a的前面,且(Case b)不能做到字典序更小的。但这是不存在的,因为(Case b)马上就能把x-1这个编号安排在a位置,即weight[a]=x-1,这样(Case a)能做的(Case b)也能做了,且(Case b)编号还更小。

所以,选择b编号x比a编号x更优。

 #include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXN 222
#define MAXM 44444
struct Edge{
int u,v,next;
}edge[MAXM];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].u=u; edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
}
int deg[MAXN],size[MAXN];
bool toposort(int n){
priority_queue<int> que;
for(int i=; i<=n; ++i){
if(deg[i]==) que.push(i);
}
for(int k=n; k>=; --k){
if(que.empty()) return ;
int u=que.top(); que.pop();
size[u]=k;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(--deg[v]==) que.push(v);
}
}
return ;
}
int main(){
int t,n,m,a,b;
scanf("%d",&t);
while(t--){
NE=;
memset(head,-,sizeof(head));
memset(deg,,sizeof(deg));
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&a,&b);
addEdge(b,a);
++deg[a];
}
if(toposort(n)){
for(int i=; i<=n; ++i) printf("%d ",size[i]);
putchar('\n');
}else puts("-1");
}
return ;
}

POJ3687 Labeling Balls(拓扑排序\贪心+Floyd)的更多相关文章

  1. POJ3687.Labeling Balls 拓扑排序

    Labeling Balls Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13201 Accepted: 3811 Descr ...

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

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

  3. [ACM] POJ 3687 Labeling Balls (拓扑排序,反向生成端)

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

  4. [poj3687]Labeling Balls_拓扑排序

    Labeling Balls poj-3687 题目大意:给出一些球之间的大小关系,求在满足这样的关系下,编号小的尽量比编号大的球的方案. 注释:1<=N(球的个数)<=200,1< ...

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

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

  6. Java实现Labeling Balls(拓扑排序的应用)

    1 问题描述 给出一些球,从1N编号,他们的重量都不相同,也用1N标记加以区分(这里真心恶毒啊,估计很多WA都是因为这里),然后给出一些约束条件,< a , b >要求编号为 a 的球必须 ...

  7. POJ3687——Labeling Balls(反向建图+拓扑排序)

    Labeling Balls DescriptionWindy has N balls of distinct weights from 1 unit to N units. Now he tries ...

  8. BZOJ_4010_[HNOI2015]菜肴制作_拓扑排序+贪心

    BZOJ_4010_[HNOI2015]菜肴制作_拓扑排序+贪心 Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜 ...

  9. POJ3687拓扑排序+贪心

    题意:       给你n个求,他们的重量是1-n(并不是说1号求的重量是1...),然后给你m组关系a,b,表示a的重量小于b的重量,然后让你输出满足要求的前提下每个球的重量,要求字典序最小. 思路 ...

随机推荐

  1. ListView异步加载网络图片完美版之双缓存技术

    本示例参考学习了一个国外的示例:http://code.google.com/p/android-imagedownloader/,有兴趣的同学下载研究一下. 问题描述:在这一篇博客中将会为大家讲解如 ...

  2. (转)搞ACM的你伤不起

    劳资六年前开始搞ACM啊!!!!!!!!!! 从此踏上了尼玛不归路啊!!!!!!!!!!!! 谁特么跟劳资讲算法是程序设计的核心啊!!!!!! 尼玛除了面试题就没见过用算法的地方啊!!!!!! 谁再跟 ...

  3. js中的闭包之我理解

    闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样. 但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的 ...

  4. PHP中冒号、endif、endwhile、endfor这些都是什么

    我们经常在wordpress一类博客程序的模板里面看到很多奇怪的PHP语法,比如:<?php if(empty($GET_['a'])): ?><font color="r ...

  5. 【转】Mybatis/Ibatis,数据库操作的返回值

    该问题,我百度了下,根本没发现什么有价值的文章:还是看源代码(详见最后附录)中的注释,最有效了!insert,返回值是:新插入行的主键(primary key):需要包含<selectKey&g ...

  6. python动态获取对象的属性和方法

    http://blog.csdn.net/kenkywu/article/details/6822220首先通过一个例子来看一下本文中可能用到的对象和相关概念.01     #coding: UTF- ...

  7. android.mk文件里的通配符

    比方你有如下目录,要编译Classes目录和Code目录下所有cpp src |-android.mk |-Classes |-A.cpp |-B.cpp |-....cpp |-Code |-E.c ...

  8. Java for LeetCode 153 Find Minimum in Rotated Sorted Array

    Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...

  9. ubuntu命令行相关命令使用心得

    一.Ubuntu解压缩zip,tar,tar.gz,tar.bz2 ZIP zip可能是目前使用得最多的文档压缩格式.它最大的优点就是在不同的操作系统平台,比如Linux, Windows以及Mac ...

  10. 奇怪的梦境(codevs 2833)

    题目描述 Description Aiden陷入了一个奇怪的梦境:他被困在一个小房子中,墙上有很多按钮,还有一个屏幕,上面显示了一些信息.屏幕上说,要将所有按钮都按下才能出去,而又给出了一些信息,说明 ...