P5049 [NOIP2018 提高组] 旅行

P5049 [NOIP2018 提高组] 旅行

题意:

一棵树(可能是基环树),从1出发,每到达一个新的点就记录下编号。求一种走法使得记录下来的编号字典序最小。
1≤n≤500000
m=n−1 或 m=n

题解:

如果不是基环树,那直接每次走字典序小的点即可
对于基环树:
第一个方法:
暴力删边将基环树变为一颗普通的树,然后计算答案,复杂度是O(n * n)
这个方法好像只能过P5022 [NOIP2018 提高组] 旅行 这个没加强数据的题,P5049过不了
第二个方法:
参考题解
对于基环树,我们在环上跑到一半,另一半通过回溯到你刚到这个环的起点,接着DFS就可以了
例如下图,我们从1开始,走3走2然后回溯3,走4,走5回溯4,最后走6
如果在环上回溯之后(图中是2回溯到3),剩下的就不需要特殊处理
在这里插入图片描述
我们把在环上的点分成三种情况:
一、其出边为环上的那个点编号是其所有未被访问的出边中最小的,如下图。
相比于6和7,4更优,所以第一种情况不需要回溯,继续环上走就行
在这里插入图片描述
二:其出边为环上的那个点编号是其所有未被访问的出边中不是最大也不是最小的,如下图
先走4,然后走6,不需要回溯,继续环上走
在这里插入图片描述

三:其出边为环上的那个点编号是其所有未被访问的出边中最大的,如下图。
先走4,再走6,再回溯2
在这里插入图片描述
总结一下:
当我们在环上走时,只要当其出边中,在环上的那个点的编号最大时,且比回溯后第一个走的点还大,这时才回溯,其他都不用回溯正常跑DFS即可
我们用flag标记是否需要回溯,用tmp记录当前节点中第一个比环上的出边的节点还要大的节点,以便后面判断是否回溯

代码:

方法一:

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define N 5010
using namespace std;
struct node{int to,next;
}a[2*N];
struct line{int x,y;
}l[2*N];
int tot,n,m,t,ls[N],in[N],state[N],w[N],ans[N],x,y,q[N];
bool k[N][N],v[N];
void addl(int x,int y)//加边
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;in[y]++;
}
bool topsort(){int l=0,r=0;for (int i=1;i<=n;i++) if(in[i]==1) q[++r]=i;while(l<r) {int now=q[++l];for (int i=ls[now];i;i=a[i].next){int y=a[i].to;if(in[y]>1){in[y]--;if(in[y]==1) q[++r]=y;}}}if(r==n) return true;return false;
}//拓扑求环
bool cmp(line x,line y)
{return x.y>y.y;}
void dfs(int x)//走一遍
{state[++t]=x;v[x]=true;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(k[x][y]||v[y]) continue;dfs(y);}
}
void check()//判断是否为更小字典序
{int i;bool flag=false;for(i=1;i<=n;i++)if(state[i]<ans[i]){flag=true;break;}else if(state[i]>ans[i]) return;if(!flag) return;for(;i<=n;i++)ans[i]=state[i];
}
void get_ans(int xs)//暴力删边
{int x=xs,b=0,i,last=0;do{w[++b]=x;in[x]=1;for(i=ls[x];i;i=a[i].next){int y=a[i].to;if(in[y]>1){x=y;break;}}}while(i);//记录环的每个点w[++b]=xs;for(int i=1;i<b;i++)//枚举删除的边{k[w[i]][w[i+1]]=k[w[i+1]][w[i]]=true;memset(v,0,sizeof(v));t=0;dfs(1);check();k[w[i]][w[i+1]]=k[w[i+1]][w[i]]=false;}
}
int main()
{memset(ans,127/3,sizeof(ans));scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);l[i]=(line){x,y};l[i+m]=(line){y,x};}sort(l+1,l+1+2*m,cmp);//排序tot=1;for(int i=1;i<=2*m;i++)//加边{addl(l[i].x,l[i].y);}if(m==n-1)//普通的树{dfs(1);for(int i=1;i<=n;i++)printf("%d ",state[i]);return 0;}topsort();for(int i=1;i<=n;i++)if(in[i]>1){get_ans(i);break;}for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}

方法二:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int N = 500010;
int n, m, vis[N], ans[N], cnt, f[N], rings[N], flag, tmp, temp, head[N], ver[N << 1], nex[N << 1], tot;
struct Node {int x, y;
}node[N << 1];
void add (int x, int y) {ver[++ tot] = y;nex[tot] = head[x];head[x] = tot;
}
bool cmp (Node a, Node b) {return a.y > b.y;
}
inline int read () {int res = 0;char ch = getchar();while (ch < '0' || ch > '9') ch = getchar();while (ch >= '0' && ch <= '9') {res = (res << 3) + (res << 1) + (ch - 48);ch = getchar();}return res;
}
void dfs (int x) {vis[x] = 1;ans[++ cnt] = x;for (int i = head[x]; i; i = nex[i]) {int y = ver[i];if (!vis[y])dfs(y);}
}
void dfsRing (int x, int fa) {if (flag) return;if (f[x] == 0) {f[x] = fa;}else if (f[x] != fa) {while (fa != x) {rings[fa] = 1;fa = f[fa];}rings[x] = 1;flag = 1;return;}for (int i = head[x]; i; i = nex[i]) {int y = ver[i];if (y == fa) continue;dfsRing(y, x);}
}
void sDfs (int x) {vis[x] = 1;ans[++ cnt] = x;if (rings[x]) { //判断x是否在环上 int flag = 0;for (int i = head[x]; i; i = nex[i]) {if (temp) break; //temp标记环上的回溯是否执行过了,因为一旦执行过环上的回溯,那么后面就不需要在环上回溯,只需正常跑DFS即可 int y = ver[i];if (vis[y]) continue;if (rings[y]) {i = nex[i];while (vis[ver[i]]) //已经被访问过的节点跳过 i = nex[i];if (i) //i不为0即环上的出边不是最大的出边 tmp = ver[i]; //tmp记录第一个比环的出边大的那个点 else if (y > tmp) { //环上的出边是最大的出边且比我们回溯后第一次要走的节点还大 flag = 1;temp = 1;}break;}}for (int i = head[x]; i; i = nex[i]) {int y = ver[i];if (vis[y]) continue;if (rings[y] && flag) continue; //flag = 1,因此回溯,不再走环上的出边 sDfs(y);}} else {for (int i = head[x]; i; i = nex[i]) {int y = ver[i];if (vis[y]) continue;sDfs(y);}}
}
int main () {n = read();m = read();for (int i = 1; i <= m; i ++) {int u = read(), v = read();node[i].x = u;node[i].y = v;node[i + m].x = v;node[i + m].y = u;}sort(node + 1, node + 2 * m + 1, cmp);for (int i = 1; i <= 2 * m; i ++)add(node[i].x, node[i].y);if (m == n - 1) {dfs(1);for (int i = 1; i <= n; i ++)printf("%d ", ans[i]);}else {dfsRing(1, 1); //一开始先找出所有在环上的点 flag = 0;tmp = 0x3f3f3f3f;sDfs(1);for (int i = 1; i <= n; i ++)printf("%d ", ans[i]);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

失配树

名字看起来挺高级的&#xff0c;然而其实就是 \(\text{KMP}\) 上树啦。 我们将每个点的 \(nex[i]\) 与 \(i\) 连边&#xff0c;那么最终 \(border\) 关系会形成一棵树&#xff0c;之后就可以在树上搞事情啦&#xff01; P5829 【模板】失配树 这题比较裸&#xff0c;直接根据定…

P7116-[NOIP2020]微信步数【数学】

正题 题目链接:https://www.luogu.com.cn/problem/P7116 题目大意 有一个kkk维空间&#xff0c;第iii维长度为wiw_iwi​&#xff0c;有nnn步每一步都是让某个维的坐标1/−11/-11/−1&#xff0c;每次走完nnn步都会从111重新走一次&#xff0c;现在求从这个空间的每个点出发走…

[2019CSP-S Day1]提高组Day1题解(格雷码[模拟(k转二进制取反的做法带证明)] + 括号树[DP] + 树上的数(暴力+菊花图+单链))

Day1T1&#xff1a;格雷码题目题解代码实现T2&#xff1a;括号树题目题解代码实现T3&#xff1a;树上的数题目10pts暴力题解代码实现25pts菊花图题解代码实现25pts单链题解代码实现T1&#xff1a;格雷码 题目 通常&#xff0c;人们习惯将所有 n位二进制串按照字典序排列&…

模板:环套树

文章目录前言解析找环代码练习环套树的直径代码thanks for reading&#xff01;前言 环套树者&#xff0c;一个环套一棵树也 解析 定义&#xff1a;n个点&#xff0c;n条边的无向连通图 其实就是树多了一条边&#xff0c;连出了一个环 性质&#xff1a;如果对环套树进行dfs&am…

使用PerfView监测.NET程序性能(四):折叠,过滤和时间范围选择

在上一篇文章使用PerfView监测.NET程序性能&#xff08;三&#xff09;&#xff1a;分组中&#xff0c;我们使用了Perfview的分组功能。分组功能旨在对某些函数按照某个格式进行分组&#xff0c;以减少视图中的各种无关函数的数量。但仅有分组还不够&#xff0c;有时我们想将一…

P1352 没有上司的舞会

P1352 没有上司的舞会 题意&#xff1a; 给你一个树&#xff0c;每个点都有权值&#xff0c;选择一些点使得权值和最大&#xff0c;要求父亲节点和子节点不能同时选择 题解&#xff1a; 经典树形dp dp[x][0]表示以x为根的子树&#xff0c;且x不参加舞会的最大快乐值 dp[x][…

基础字符串

初三巨佬djwj233 基础字符串

CF536C-Tavas and Pashmaks【凸壳】

正题 题目链接:https://codeforces.com/contest/536/problem/C 题目大意 nnn个人&#xff0c;第iii个人的游泳速度sis_isi​&#xff0c;跑步速度是rir_iri​。如果跑道长度是RRR&#xff0c;泳道长度是SSS那么一个人的用时就是RriSsi\frac{R}{r_i}\frac{S}{s_i}ri​R​si​S​…

带旋treap概念及模板,带例题:普通平衡树

带旋Treap二叉查找树BST(Binary Search Tree)定义Treap定义模板合集&#xff08;均为O(logn)O(logn)O(logn)&#xff09;push_up模板旋转模板插入模板删除模板查找前驱模板查找后驱模板查找键值key模板查找节点的修正值rank模板PS&#xff1a;rd的比较问题例题&#xff1a;普通…

微服务系列实践 .NET CORE

从事这个行业转眼已经6年了&#xff0c;从当初刚毕业的在北京朝八晚十&#xff0c;从二环到五环&#xff0c;仍每天精力充沛的小愤青&#xff1b;再到深圳一点一滴的辛勤在软件行业的耕种&#xff0c;从当初单体应用架构到现在微服务架构的经历&#xff0c;回想起来自己的收获倒…

P2607 [ZJOI2008]骑士

P2607 [ZJOI2008]骑士 题意&#xff1a; n个点n个边&#xff0c;每个点都有权值&#xff0c;相邻的点不能同时选择&#xff0c;问如何选择能使得权值最大 题解&#xff1a; 这个题很有P1352 没有上司的舞会这个题的感觉&#xff0c;唯一的区别是那个题保证是树&#xff0c;…

模板:线段树优化建图

前言 百川到海&#xff0c;天下归一 解析 线段树优化建图是用于对一个区间的点连边时的优化方法 建一棵in树一棵出树分别往上和下指即可 大概长这样 &#xff08;pia的洛谷的照片&#xff09; 建树 正常动态开点即可 void build(int &k,int l,int r){tr[ktot](tree){0…

Binary Search

01 分数划分 什么 01 分数划分&#xff0c;叫 Binary Search 多好。 P1642 规划 可以二分答案 \(x\)&#xff0c;考虑选择 \(n-m\) 个数使得答案 \(\ge x\)。 \[\dfrac{\sum w(i)}{\sum c(i)}\ge x \]\[\sum w(i)\ge \sum (x\times c(i)) \]\[\sum(w(i)-x\times c(i))\ge 0 \]之…

CF1556F-Sports Betting【状压dp,数学期望】

正题 题目链接:https://www.luogu.com.cn/problem/CF1556F 题目大意 nnn个点的一张竞赛图&#xff0c;每个点有一个权值aia_iai​&#xff0c;(i,j)(i,j)(i,j)之间的边iii连jjj的概率是aiaiaj\frac{a_i}{a_ia_j}ai​aj​ai​​&#xff0c;否则jjj连iii。 现在期望有多少个点…

[非旋平衡树]fhq_treap概念及模板,例题:普通平衡树,文艺线段树

文章目录概念全套模板push_up模板split拆树模板(按权值拆)split拆树模板(按个数拆)merge合并模板&#xff08;地址版&#xff09;merge合并模板&#xff08;带返回根&#xff09;区间模板insert插入模板delete删除模板find_kth找第k大模板get_rank找排名模板pre找前驱模板suf找…

P4381 [IOI2008]Island

P4381 [IOI2008]Island 题意&#xff1a; 给你一棵基环树森林&#xff0c;求出基环树的直径之和. 题解&#xff1a; 对于基环树,我们将环看作根,那么直径有两种情况:: 1.不经过环,也就是环上某个点的子树内部,对于这种情况,直接在子树内部处理直径,更新答案即可; 2.经过环…

20210912模拟

文章目录总结复盘总结 190pts 50403070 今天吸取了昨天的教训&#xff0c;没有再像之前一样先死磕一道题&#xff0c;把命运押在切题上&#xff0c;整体时间分配还算合理 要认真审题&#xff01; 今天T1少看了条件&#xff0c;T4一开始看错题意浪费了时间… 复盘 先看题 乍…

surging 微服务引擎 1.0 正式发布

surging 是一个分布式微服务引擎,提供高性能RPC远程服务调用&#xff0c;服务引擎支持http、TCP、WS、Mqtt协议,采用Zookeeper、Consul作为surging服务的注册中心&#xff0c;集成了哈希一致性&#xff0c;随机&#xff0c;轮询、压力最小优先作为负载均衡的算法&#xff0c;底…

CF1594F-Ideal Farm【构造】

正题 题目链接:https://www.luogu.com.cn/problem/CF1594F 题目大意 给出n,s,kn,s,kn,s,k&#xff0c;求是否所有的长度为nnn且和为sss的正整数序列都有一段和为kkk的区间。 1≤T≤105,1≤n,s,k≤10181\leq T\leq 10^5,1\leq n,s,k\leq 10^{18}1≤T≤105,1≤n,s,k≤1018 解题…

P4178 Tree

P4178 Tree 题意&#xff1a; 给定一棵 n 个节点的树&#xff0c;每条边有边权&#xff0c;求出树上两点距离小于等于 k 的点对数量。 题解&#xff1a; 点分治的模板题是求等于K的路径条数 本题是求小于等于K的路径条数&#xff0c;我们只需要改变统计答案即可 原本统计答…