题目是要给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. 一个很不错的适合PHPER们书单,推荐给大家【转】

    来我博客的访客们中,有一些是PHP的初学者,是不是很迷茫PHP应该怎么学?应该买什么样的书?到处问人,到处求助?这下好了. 正好看到黑夜路人在博客上推荐了一个书单,看上去都非常不错,很多我也没有读过, ...

  2. 如何下载google play免费应用的apk文件

    到这里: http://apps.evozi.com/apk-downloader/ 一看便知.

  3. intellij idea 如何更改编辑器文本字体和大小

    换上了intellij idea之后,第一件事就是想要改变下文字字体,因为在我这个27寸的2k分辨率的屏幕上,文字显然太小了. intellij idea字体设值分成两部分,一部分是UI部分字体字号设 ...

  4. oracle通过plsql导入dmp数据文件

    首先安装Oracle,新建一个空的数据库mydb 从开始菜单运行cmd控制台:sqlplus "用户名/密码@数据库名 as sysdba"//例如sqlplus sys/admi ...

  5. July 27th, Week 31st Wednesday, 2016

    Don't let yesterday take up too much of today. 别让昨天的事情占据今天太多时间. Learn from yesterday, but don't let ...

  6. python基础——递归函数

    python基础——递归函数 递归函数 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数.举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用 ...

  7. WebService之CXF框架

    本文主要包括以下内容 ant工具的使用 利用cxf实现webservice cxf与spring整合 ajax访问webservice ant 工具 1.为什么要用到ant这个工具呢? Ant做为一种 ...

  8. 一、HTML和CSS基础--网页布局--如何用css进行网页布局

    什么叫做布局? 又称版式布局,是网页UI设计师将有限的视觉元素进行有机的排列组合. 网页设计的特点 网页可以自适应宽度 网页的高度理论上可以无限延长 网页分栏 分栏又称为分列,常见的布局分为:一列布局 ...

  9. 批量传递ID数组字符串到后台的处理

    js代码: $(function () { $("#btnTest").click(function () { var array = new Array(); array.pus ...

  10. jquery之别踩白块游戏的实现

    转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5687112.html 前端学习要告一段落了,也没机会写什么像样的东西,然后无意中想起某人以前给我玩了一下别踩白块的游 ...