原题链接  https://www.luogu.org/problem/P5022

本着快csp了,做点往年的NOIp的题试试水来着,没想到水这么深 难度还挺大的,耗了我一天的时间(可能是我太菜了)

题目大意:

给你 n 个点和 m 条边,问如何遍历每个结点才能使最后的字典序最小,注意只有遍历完一棵字树的所有结点后才能回溯到他的父亲结点;

前 60 pts:

作为 NOIp2018 day2T1 来说,部分分确实给的挺足的,这 60 pts 就是哦;

看到 m = n-1 说明这是一棵树,考虑用搜索:

既然要保证是字典序最小,那么我们第一个点一定要选 1 了,考虑接下来只需要从他的儿子里按照编号从小到大遍历就好了,注意要遍历完一棵子树才能回溯上去;

后 40 pts:

m = n ?嗯,基环树!

所谓基环树,就是说在一个图里,有 n 个结点和 n 条边,那么这个图内有且仅有一个环;

我们仍然可以按照前 60 pts 的做法上去想:

按理来说我们遍历完 n 个结点只需要走 n-1 条边就好了啊,所以一定有一条边是多余的,也就是说我们根本遍历不到它,那么我们可以枚举每一条边,暂时把它删掉,然后和刚才的做法一样跑一遍 dfs,这样能求得一个字典序,我们取所有字典序中最小的一个就是答案了;

优化

显然如果我们像上述做法那样暴力的话,是会有几个点 TLE 的(毕竟NOIp也不会水到这种程度吧qwq),所以我们要考虑优化;

优化一:

题目中说了,我们的目的是遍历完每个点,那么假设我们删掉的边不是环上的边,那么这个图一定会变得不连通,那么就无法完成任务了;

所以我们只要找出基环树上的环,只需删掉环上的边就好了,至于找环嘛,这里我用的 tarjan(其实是只会这个qwq)

优化二:

最优性剪枝:假如我们在 dfs 的过程中,发现求得的字典序不如之前的答案优,那么我们直接可以 return 了;

有了这两个小优化,终于可以愉快的 AC 本题了,时间复杂度 O(n2);

至于更神仙的 O(n log n)甚至 O(n)的做法,咕咕咕~

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. int read()
  8. {
  9. char ch=getchar();
  10. int a=,x=;
  11. while(ch<''||ch>'')
  12. {
  13. if(ch=='-') x=-x;
  14. ch=getchar();
  15. }
  16. while(ch>=''&&ch<='')
  17. {
  18. a=(a<<)+(a<<)+(ch-'');
  19. ch=getchar();
  20. }
  21. return a*x;
  22. }
  23. const int N=;
  24. int n,m,bi,bj,tot,top,tim,start,edge_sum,scc_sum,ans_sum=;
  25. int u[N],v[N],dfn[N],low[N],scc[N],st[N],vis[N],size[N],head[N],ans[N],f[N][N];
  26. struct node
  27. {
  28. int to,next;
  29. }a[N<<];
  30. void add(int from,int to) //链表存图
  31. {
  32. edge_sum++;
  33. a[edge_sum].to=to;
  34. a[edge_sum].next=head[from];
  35. head[from]=edge_sum;
  36. }
  37. void tarjan(int u,int fa) //tarjan找环
  38. {
  39. dfn[u]=low[u]=++tim;
  40. st[++top]=u;
  41. vis[u]=;
  42. for(int i=head[u];i;i=a[i].next)
  43. {
  44. int v=a[i].to;
  45. if(v==fa) continue;
  46. if(!dfn[v])
  47. {
  48. tarjan(v,u);
  49. low[u]=min(low[u],low[v]);
  50. }
  51. else if(vis[v]) low[u]=min(low[u],dfn[v]);
  52. }
  53. if(dfn[u]==low[u])
  54. {
  55. scc_sum++;
  56. if(u==) start=scc_sum;
  57. while(st[top]!=u)
  58. {
  59. vis[st[top]]=;
  60. scc[st[top]]=scc_sum;
  61. top--;
  62. }
  63. vis[st[top]]=;
  64. scc[st[top]]=scc_sum;
  65. top--;
  66. }
  67. }
  68. void dfs(int u,int fa)
  69. {
  70. tot++;
  71. if(u<ans[tot]||bj) //如果比答案更优,或者之前就已经比答案优的话,就更新答案
  72. {
  73. bj=; //发现更优解了
  74. ans[tot]=u;
  75. }
  76. else if(u>ans[tot]) //最优性剪枝:不如答案优就直接返回
  77. {
  78. bi=; //没有找到更优解
  79. return ;
  80. }
  81. vis[u]=;
  82. for(int i=;i<=n;i++) //从小到大去枚举每个点
  83. {
  84. if(i!=fa&&f[u][i]&&!vis[i]) //判断是否连接
  85. {
  86. dfs(i,u);
  87. if(bi) return ; //剪枝
  88. }
  89. }
  90. }
  91. int main()
  92. {
  93. n=read();m=read();
  94. for(int i=;i<=m;i++)
  95. {
  96. u[i]=read();v[i]=read();
  97. add(u[i],v[i]);add(v[i],u[i]); //链表存图,tarjan的时候方便
  98. f[u[i]][v[i]]=;f[v[i]][u[i]]=; //邻接矩阵存图,选择贪心决策的时候方便从小到大找儿子
  99. }
  100. for(int i=;i<=n;i++) //tarjan找环
  101. {
  102. if(!dfn[i]) tarjan(i,);
  103. }
  104. memset(ans,0x3f,sizeof(ans));
  105. if(m==n-) //前60pts
  106. {
  107. dfs(,);
  108. for(int i=;i<=n;i++) printf("%d ",ans[i]);
  109. return ;
  110. }
  111. else //后40pts:基环树
  112. {
  113. for(int i=;i<=m;i++)
  114. {
  115. if(scc[u[i]]==scc[v[i]]) //只需删除同一联通块里的边
  116. {
  117. tot=;bi=;bj=; //bi表示是否一定不会找到更优解,bj表示是否找到了更优解
  118. memset(vis,,sizeof(vis));
  119. f[u[i]][v[i]]=; //暂时删边,这里用邻接矩阵就比较方便了
  120. f[v[i]][u[i]]=;
  121. dfs(,); //更新答案
  122. f[u[i]][v[i]]=; //记得恢复
  123. f[v[i]][u[i]]=;
  124. }
  125. }
  126. }
  127. for(int i=;i<=n;i++) printf("%d ",ans[i]);
  128. return ;
  129. }

P5022 旅行的更多相关文章

  1. 【题解】 P5022旅行

    [题解]P5022 旅行 当给定你一颗树的时候,这题就是一道送分题,凉心啊! 但是给定你一颗基环树呢? 暴力断环直接跑. 但是数据范围\(n\le 1000\) 乱做就完事了. 考场上这样想的,对于\ ...

  2. 【luogu P5022 旅行】 题解

    题目连接:https://www.luogu.org/problemnew/show/P5022 \(NOIP2018 DAY2T1\) 考场上只写了60分,很容易想到当 m = n - 1 时的树的 ...

  3. 洛谷 P5022 旅行——题解

    发现大部分题解都是O(n^2)的复杂度,这里分享一个O(n)复杂度的方法. 题目传送 首先前60%的情况,图是一棵无根树,只要从1开始DFS,每次贪心走点的编号最小的点就行了.(为什么?因为当走到一个 ...

  4. 洛谷P5022 旅行 题解 去环/搜索

    题目链接:https://www.luogu.org/problem/P5022 这道题目一开始看的时候没有思路,但是看到数据范围里面有一个: \(m = n-1\) 或 \(m = n\) ,一下子 ...

  5. P5022 旅行 (NOIP2018)

    传送门 先考虑是一颗树的情况 求最小的 dfs 序 显然按儿子编号从小到大dfs 如果有多一条边怎么办 显然会有一条边不用走 直接枚举删那条边然后每次都暴力 dfs 复杂度 $O(n^2)$ 注意每个 ...

  6. Luogu P5022 旅行

    开始写复赛题了 先放张图纪念我惨烈的卡常之路 不说了,简直悲伤 题目链接 思路么..不想写了 Code //不要在意四十行超级加速,卡常用的 #include<bits/stdc++.h> ...

  7. P5022 旅行[基环树]

    以后必须学会面向数据编程!看半天题目不知道咋写直接爆搜,结果分少的可怜,还不如直接贪搞个60分. 观察数据,发现图至多存在一个环. 显然,如果没有环,这个题不跟你多bb,直接贪就完事了,线性复杂度. ...

  8. 洛谷P5022 旅行 题解

    前面几个代码都是部分分代码,最后一个才是AC了的,所以最后一个有详细注释 安利一发自己的Blog 这是提高组真题,233有点欧拉回路的感觉. 题目大意: 一个 连通 图,双向边 ,无重边 , 访问图中 ...

  9. Luogu P5022 旅行 搜索+贪心

    好吧...一直咕..现在才过...被卡常卡到爆... 写的垃圾版本,$n^2$无脑删边..可以发现走出来的是棵树...更优秀的及数据加强版先咕着...一定写.qwq #include<cstdi ...

随机推荐

  1. 3.asp.net core 关键概念

    1. StartUp类 在Startup.ConfigureServices方法里配置或注册服务 在Startup.Configure方法里配置请求处理管道.请求处理管道由一系列中间件组建构成,每个中 ...

  2. Go 终端读写 && 文件读写、copy

    终端读写 操作终端相关文件句柄常量 os.Stdin(standard):标准输入 os.Stdout:标准输出 os.Stderr:标准错误输出 标准输出 demo:直接输出和 判断之后输出的结果不 ...

  3. ribbon的理解

    什么是ribbon? Ribbo是一个基于HTTP和TCP的客户端负载均衡器 什么是客户端负载均衡? 客户端负载均衡和服务端负载均衡最大的区别在于服务清单所存储的位置. 在客户端负载均衡中,所有的客户 ...

  4. js钩子函数实现一个简单动画

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  5. U盘因格式化 NTFS 中断造成无法识别,生产平台同样无法识别的修复处理方案

    特征: 电脑设备管理器(win10):识别到大容量存储设备 电脑磁盘管理:识别可移动磁盘无媒体 ChipGenius(v4_19_0319):能识别到制造商,但识别不到芯片具体型号 U盘相关生产平台: ...

  6. webdispatch配置

    PRDPISP01:/sapmnt/WIP/profile # su - wipadm PRDPISP01:wipadm 23> cdpro PRDPISP01:wipadm 24> ls ...

  7. 在oracle中存入date类型数据遇到的问题及其解决方法(利用java.sql.date和Timestamp)

    转自:https://blog.csdn.net/ShadowerWArden/article/details/80652377 1. 使用JDBC操作Oracle数据库时,使用java.sql.Da ...

  8. Windows Server 2012 R2上安装.Net4.6.1出错

    在Windows Server 2012 R2上安装.Net4.6.1时提示“你需要先安装对应于 KB2919355 的更新,然后才可在……”解决方式: 在官网下载更新包,下载地址:https://w ...

  9. [#Linux] CentOS 7 美化调优

    优化美化系统,是为了让新系统能更顺眼顺手,符合自己过去在windows下的使用习惯,从而实现平稳过渡. 正如开篇时谈到的,现在的桌面版linux已相当友好(特别是Ubuntu),基本不需要做什么额外设 ...

  10. Python面向对象之多态、封装

    一.多态 超过一个子类继承父类,出现了多种的形态. 例如,动物种类出现了多种形态,比如猫.狗.猪 class Animal:pass class Cat(Animal):pass class Dog( ...