Poj 3687 Labeling Balls[拓扑排序]

2024-06-07 03:58

本文主要是介绍Poj 3687 Labeling Balls[拓扑排序],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:点击打开链接

很给力的道题,拓扑排序的应用,算是对TopSort认识更深了吧。

拓扑排序这里不做过多的解释,主要来说这道题的应用。

题目的意思就是给1——N质量的N个球贴标签,要求就是满足要求下的标签小的尽量轻。

没什么深入想,直接TopSort。果断WA,WA的。后来看题,发现了很多的问题。输出的是Label1-LabelN标签的重量。还有很多的问题没有看太清晰。

再看了几遍题意后,还是WA WA的。果断不知道怎么弄了。

拿来一组数据比较了一下,果断ANSWER是错误的。

后来我都有点混乱了。

我可以有两种操作:

一,我找到满足条件的质量最小的一次贴标签。

二,我还是找到满足条件的最小的标签给质量依次贴。

权衡操作复杂度来看,第一种比较简单。

上WA的代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;const int N=205;
bool vis[N];
int n,m,Enter[N];
vector<int> map[N];void TopSort(){int q[N],top=1;while(1){int cnt=0,p;for(int i=n;i>=1;i--)if(Enter[i]==0&&!vis[i]){cnt++;p=i;}if(cnt==0) break;else q[p]=top++;for(int i=0;i<map[p].size();i++)Enter[map[p][i]]--;vis[p]=true;}if(top-1==n){for(int i=1;i<=n;i++){for(int j=1;j<=top;j++)if(q[j]==i) printf("%d ",j);}}else printf("-1");printf("\n");
}
int main(){int T;scanf("%d",&T);while(T--){CLR(vis,0);CLR(Enter,0);CLR(map,0);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);map[a].push_back(b);Enter[b]++;}TopSort();}return 0;
}

比如这组数据

5 4

1 4

4 2

5 3

3 2

错误的程序错误输出为:

1 4 5 3 2

通过手模拟我们可以知道:

1 5 3 4 2

这是为什么呢???

因为,单入度为0的节点有多个的时候 ,我们选择的标准应该是什么?

有很多的朋友肯定会说当然是选择质量最小的啊。对,我也是这么想的。

但是,如果这样做的话,就会出现,后面出现更小的质量同样也满足条件。

比如 假设 1 3 5 4 2 和 1 5 3 4 2这两种, 条件同样满足。但是5先出现了入度为0 的情况。这样就不对了。

经过百度加上自己的理解,学会了普遍的反向建图的方法。

正确代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;const int N=205;
bool vis[N];
int n,m,Enter[N];
bool map[N][N];void TopSort(){int q[N],top=n;while(top>0){int cnt=0,p;for(int i=1;i<=n;i++)if(Enter[i]==0&&!vis[i]){cnt++;p=i;}//面对多个入度为0的节点时,我们该怎么处理?//是 将小的节点进入序列 删边 再重新选点//还是 将所有的节点进入序列 删边 再选点?if(cnt==0) break;else q[top--]=p;for(int i=1;i<=n;i++)if(map[p][i]) Enter[i]--;vis[p]=true;}if(top==0){//这里明显是找到合适的标签贴到ball上.for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)if(q[j]==i) printf("%d%c",j,i==n?'\n':' ');}}else printf("-1\n");
}
int main(){int T;scanf("%d",&T);while(T--){CLR(vis,0);CLR(Enter,0);CLR(map,0);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);if(!map[b][a]){map[b][a]=true;Enter[a]++;}}TopSort();}return 0;
}

反向建图,找最大的标签给最大质量的ball贴。
这里吧第一种操作和第二种操作搞晕了。

如果你是第一种操作那么相当于把标签的顺序已经排好(1-n),需要挑选合适质量的球。

第二种,反之。

好题。!


这篇关于Poj 3687 Labeling Balls[拓扑排序]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038105

相关文章

数据结构9——排序

一、冒泡排序 冒泡排序(Bubble Sort),顾名思义,就是指越小的元素会经由交换慢慢“浮”到数列的顶端。 算法原理 从左到右,依次比较相邻的元素大小,更大的元素交换到右边;从第一组相邻元素比较到最后一组相邻元素,这一步结束最后一个元素必然是参与比较的元素中最大的元素;按照大的居右原则,重新从左到后比较,前一轮中得到的最后一个元素不参4与比较,得出新一轮的最大元素;按照上述规则,每一轮结

七种排序方式总结

/*2018.01.23*A:YUAN*T:其中排序算法:冒泡排序,简单排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序*/#include <stdio.h>#include <math.h>#include <malloc.h>#define MAXSIZE 10000#define FALSE 0#define TRUE 1typedef struct {i

拓扑排序——C语言

拓扑排序(Topological Sorting)是一种用于有向无环图(DAG)的排序算法,其输出是图中所有顶点的线性排序,使得对于每条有向边 (u, v),顶点 u 在 v 之前出现。拓扑排序确定了项目网络图中的起始事件和终止事件,也就是顶点的执行顺序。         因为是有向无环图,所以拓扑排序的作用其实就是把先发生的排序在前面,后发生的排序到后面。 例如现在我们有一个

嵌入式学习——数据结构(哈希、排序)——day50

1. 查找二叉树、搜索二叉树、平衡二叉树 2. 哈希表——人的身份证——哈希函数 3. 哈希冲突、哈希矛盾 4. 哈希代码 4.1 创建哈希表 4.2  5. 算法设计 5.1 正确性 5.2 可读性(高内聚、低耦合) 5.3 健壮性 5.4 高效率(时间复杂度)时间复杂度越低,效率越高, 5.5 低储存(空间复杂度)空间复杂度越低,存储空间越少 6.排序算法 6.1 冒

poj 3882(Stammering Aliens) 后缀数组 或者 hash

后缀数组:  构建后缀数组,注意要在字符串莫末尾加上一个没出现过的字符。然后可以2分或者直接扫描,直接扫描需要用单调队列来维护 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string

poj 3294(Life Forms) 2分+ 后缀数组

我曾用字符串hash写,但是超时了。只能用后最数组了。大致思路:用不同的符号吧字符串连接起来,构建后缀数组,然后2分答案,依次扫描后缀数组,看是否瞒住条件。 VIEW CODE #include<cstdio>#include<vector>#include<cmath>#include<algorithm>#include<cstring>#include<cassert>#

poj 2391 Ombrophobic Bovines (网络流)

这是一道很经典的网络流的题目。首先我们考虑假如我们的时间为无穷大。我们吧每个点拆成2个点 i和i' .。虚拟源点s和汇点t。对于每个点建边(s,i, a[i])  (i‘,t,ib[i]) 。 其中a[i]为给点有多少牛,b[i]为容量。i和j连通 建边 (i,j',inf);如果最大流==所有牛的个数,就可能装下所有的牛。那么现在我们考虑时间。假设最大时间为T.那么如果i到j的的最短时间>T

poj 1330 LCA 最近公共祖先

水题目。直接上代码了。 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string>#include<cstring>#include<map>#include<vector>#

poj 3160 Father Christmas flymouse 强连通+dp

首先我们可以确定的是,对于val值小于0的节点都变成0.   假设一个集合内2个房间都能任意到达,那么我就可以吧集合内的所有点的价值都取到,并且可以达到任一点。实际上集合内的每个点是相同的,这样的集合就是一个强连通分量。 那么我们就可以用tarjin算法进行强连通缩点, 最后形成一个dag的图。在dag的图上面进行dp。可以先用拓扑排序后dp。或者建反响边记忆化搜索 。 VIEW

leetcode刷题(40)——83. 删除排序链表中的重复元素

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 示例 1: 输入: 1->1->2 输出: 1->2 示例 2: 输入: 1->1->2->3->3 输出: 1->2->3 平时我们删除一个链表中的某个元素,一般都是以下的写法: temp.next = temp.next.next; 这样temp.next就被删除了 此题解法如下: class Solution