题目大意:输入一颗无根树的括号序列,求这棵树的普吕弗序列。

分析思路:

1)普吕弗序列,可以参考维基百科,其做法是找出树中编号最小的叶子节点,并将此叶子节点及边删除,并输出其邻接的节点标号;

2)递归地构造树,可以使用list<int> 数组来表示一个“邻接表”,以存储构造的树;

3)使用优先队列来进行删除,奈何priority_queue没有迭代器访问,只能用堆排序,取最值;

代码:

  1. #include<iostream>
  2. #include<vector>
  3. #include<map>
  4. #include<queue>
  5. #include<string>
  6. #include<algorithm>
  7. #include<fstream>
  8. #include<list>
  9. using namespace std;
  10.  
  11. struct nodeAndDegree
  12. {
  13. int degree; //度
  14. int nodeNumber; //结点编号
  15. bool operator < (const nodeAndDegree& n1)const
  16. {
  17. return degree == n1.degree ? (nodeNumber > n1.nodeNumber) : (degree > n1.degree);
  18. }
  19. };
  20.  
  21. const int MAX_LEN = 55;
  22. list<int> vGraph[MAX_LEN];
  23. vector<int> v;
  24. int rootNumber = 0;
  25.  
  26. void dfs(int start, int end, int parent, string str)
  27. {
  28. if (start == end) //只有单个点
  29. {
  30. return;
  31. }
  32.  
  33. //放入邻接矩阵
  34. int currentNode = 0;
  35. for (int i = start + 1; i <= end - 1; i++)
  36. {
  37. if (str[i] == ' ' || str[i] == '\0' || str[i] == '(')
  38. {
  39. break;
  40. }
  41. currentNode = currentNode * 10 + (int)(str[i] - 48);
  42. }
  43.  
  44. //放入邻接矩阵
  45. vGraph[parent].push_back(currentNode);
  46. vGraph[currentNode].push_back(parent);
  47. v.push_back(currentNode);
  48.  
  49. int mark = 0;
  50. int tmpStart = -1;
  51. for (int i = start + 1; i <= end - 1; i++)
  52. {
  53. if (str[i] == '(')
  54. {
  55. mark++;
  56. if (tmpStart == -1) tmpStart = i;
  57. continue;
  58. }
  59.  
  60. if (str[i] == ')')
  61. {
  62. mark--;
  63. if (mark == 0)
  64. {
  65. dfs(tmpStart, i, currentNode, str);
  66. tmpStart = -1;
  67. }
  68. }
  69. }
  70. }
  71.  
  72. void print_prufer_sequnce()
  73. {
  74. //首先修改根节点对应的长度
  75. int tmp = vGraph[0].front();
  76. vGraph[tmp].remove(0);
  77.  
  78. vector<nodeAndDegree> listNodeDegree;
  79. for (int i = 0; i < v.size(); i++)
  80. {
  81. nodeAndDegree *nd = new nodeAndDegree();
  82. nd->nodeNumber = v[i];
  83. nd->degree = vGraph[v[i]].size();
  84.  
  85. listNodeDegree.push_back(*nd);
  86. }
  87.  
  88. int n = v.size() - 1;
  89. int index = 0;
  90.  
  91. while (index < n)
  92. {
  93. make_heap(listNodeDegree.begin(), listNodeDegree.end());
  94. int number = listNodeDegree[0].nodeNumber; //当前结点
  95. int front = vGraph[number].front();
  96.  
  97. cout << front ;
  98. if (index != n - 1)
  99. {
  100. cout << " ";
  101. }
  102. vGraph[front].remove(number);
  103. vGraph[number].remove(front);
  104. for (int j = 1; j < listNodeDegree.size(); j++)
  105. {
  106. if (listNodeDegree[j].nodeNumber == front)
  107. {
  108. listNodeDegree[j].degree--;
  109. break;
  110. }
  111. }
  112.  
  113. listNodeDegree.erase(listNodeDegree.begin());
  114.  
  115. index++;
  116. }
  117. }
  118.  
  119. int main()
  120. {
  121. string s;
  122. //fstream cin("1097.txt");
  123. while (getline(cin, s))
  124. {
  125. for (int i = 0; i < MAX_LEN; i++)
  126. {
  127. vGraph[i].clear();
  128. }
  129. v.clear();
  130. dfs(0, s.size() - 1, 0, s);
  131. print_prufer_sequnce();
  132. cout << endl;
  133. }
  134. return 0;
  135. }

以纪念我那逝去的耗费精力的兴奋的AC。

zoj 1097 普吕弗序列的更多相关文章

  1. 线性时间构造普吕弗(Prüfer)序列

    tree -> sequence 首先预处理数组 deg[N], deg[i]表示编号为i的节点的度数,我们每次要删除的节点肯定是 满足deg[i]=1 的编号最小节点, 首先找到所有叶子并选出 ...

  2. 计蒜客NOIP模拟赛(2) D2T1 劫富济贫

    [问题描述] 吕弗·普自小从英国长大,受到骑士精神的影响,吕弗·普的梦想便是成为一位劫富济贫的骑士. 吕弗·普拿到了一份全国富豪的名单(不在名单上的都是穷人),上面写着所有富豪的名字以及他们的总资产, ...

  3. hdu 1394 zoj 1484 求旋转序列的逆序数(并归排序)

    题意:给出一序列,你可以循环移动它(就是把后面的一段移动到前面),问可以移动的并产生的最小逆序数. 求逆序可以用并归排序,复杂度为O(nlogn),但是如果每移动一次就求一次的话肯定会超时,网上题解都 ...

  4. 无向图的完美消除序列 判断弦图 ZOJ 1015 Fish net

       ZOJ1015 题意简述:给定一个无向图,判断是否存在一个长度大于3的环路,且其上没有弦(连接环上不同两点的边且不在环上). 命题等价于该图是否存在完美消除序列. 所谓完美消除序列:在 vi,v ...

  5. ZOJ 3963 Heap Partition set维护。给一个序列,将其划分成尽量少的序列,使每一个序列满足按照顺序构造二叉树,父母的值<=孩子的值。

    Heap Partition Time Limit: Seconds Memory Limit: KB Special Judge A sequence S = {s1, s2, ..., sn} i ...

  6. ZOJ 3795 Grouping 求最长链序列露点拓扑

    意甲冠军:特定n积分.m向边条. 该点被划分成多个集合随机的每个集合,使得2问题的关键是无法访问(集合只能容纳一个点) 问至少需要被分成几个集合. 假设没有戒指,接着这个话题正在寻求产业链最长的一个有 ...

  7. (队列的应用5.3.1)ZOJ 3210 A Stack or A Queue?根据进入结构的序列和离开结构的序列确定是stack还是queue)

    /* * ZOJ_3210.cpp * * Created on: 2013年10月30日 * Author: Administrator */ #include <iostream> # ...

  8. ZOJ 2319 Beatuiful People(单调递增序列的变形)

    Beautiful People Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge The most prest ...

  9. 弗拉特利定律:Illumina怎样缔造基因革命

    蕾妮·瓦林特(Renee Valint)的女儿谢尔碧(Shelby)在2000年出生时.看起来虚弱无力,就如同一仅仅耷拉着的布娃娃.谢尔碧学着走路和说话,但学得很慢.错过了儿童发展的重要阶段.到4岁时 ...

随机推荐

  1. [ruby on rails] 跟我学之(5)显示所有数据

    之前的index页,显示的是hello world,现在将其修改为显示我们在rails console里面录入的数据. 1. 修改action 如之前的章节<[ruby on rails] 跟我 ...

  2. 在Java中>、>>、>>>三者的区别

    Java,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称.用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力 ...

  3. 【转】Spring@Autowired注解与自动装配

    1   配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ...

  4. iOS 中NSOperationQueue,Grand Central Dispatch , Thread的上下关系和区别

    In OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central D ...

  5. block引发的陷阱

    block在项目的开发中使用时非常频繁的,苹果官方也极力推荐使用block.其实,究其本质,block就是指向结构体的指针(可利用运行时机制查看底层生成的c代码).然而在使用block时会存在很多陷阱 ...

  6. Gym 100801A Alex Origami Squares (求正方形边长)

    题目:传送门.(需要下载PDF) 题意:给定一个长方形,在长方形内部画三个相同的正方形,问正方形的边长最大是多大. 题解:根据长宽比例可以算出三种情况,如果长比宽大三倍以上,那么正方形边长就是宽:如果 ...

  7. Android Handler leak 分析及解决办法

    In Android, Handler classes should be static or leaks might occur, Messages enqueued on the applicat ...

  8. 比较两个目录中的文件 diff -rq

    [root@bass test]# mkdir A B [root@bass test]# tree A A └── lin 0 directories, 1 file [root@bass test ...

  9. Sublime Text : 创建工程

    Sublime Text 可以很方便地管理多个工程.使用Sublime Text的Projects,可以将不同根目录的文件组织起来成为一个工程,而不用将所有的文件都放到一个根目录下面. 1. 创建工程 ...

  10. oracle 执行计划详解

    简介:     本文全面详细介绍oracle执行计划的相关的概念,访问数据的存取方法,表之间的连接等内容.     并有总结和概述,便于理解与记忆! +++ 目录 ---     一.相关的概念    ...