题解 P5022 【旅行】

chen_zhe

2018-11-17 22:45:51

Solution

写一篇简单的题解造福社会。 对于树上的情况,能参加提高组的oier都应该可以想出来只要给一个点所能到达的点的编号进行一次从小到大的排序的贪心思想,在树上dfs一遍即可解决。 但是对于基环树上的情况呢?这个就有区分度了。~~考场上的我看到基环树想都没想就跑t2了~~ 似乎有很多人会以为用一个priority_queue维护可以到达(包括绕回去)的点即可,实际上可以构造出很多反例,例如这一棵基环树 ![](https://cdn.luogu.com.cn/upload/pic/43845.png) 你如果想要用优先队列维护,答案是`123456`,然而正确答案显然为`123645`。那么如何解决呢? 我们可以考虑删边进行这个操作。基环树有一个很好的性质,删了一条边就变成一棵树。如果我们手玩一下基环树的样例可以发现:必定有一条边是不会经过的,因此就可以想到删边,然后类似于在树上进行贪心的思路即可。 代码也就很简单了。我个人认为代码可读性很高。 ``` #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cctype> #include <vector> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } int n,m; vector <int> G[5050]; int ans[5050],edge[5050][2]; namespace solve1 { int cnt=0; bool vis[5050]; inline void dfs(int u,int fa) { ans[++cnt]=u; vis[u]=true; for (int i=0;i<G[u].size();i++) { int v=G[u][i]; if (!vis[v]) dfs(v,u); } } void main() { memset(ans,0,sizeof(ans)); memset(vis,0,sizeof(vis)); cnt=0; for (int i=1;i<=n;i++) sort(G[i].begin(),G[i].end()); dfs(1,0); for (int i=1;i<=n;i++) printf("%d ",ans[i]); } } namespace solve2 { int cnt=0,res[5050]; bool vis[5050]; inline bool comp() { for (int i=1;i<=n;i++) if (ans[i]!=res[i]) return ans[i]>res[i]; return false; } int del_u,del_v; inline bool check(int u,int v) { if ((u==del_u && v==del_v) || (u==del_v && v==del_u)) return false; return true; } inline void dfs(int u,int fa) { res[++cnt]=u; vis[u]=true; for (int i=0;i<G[u].size();i++) { int v=G[u][i]; //cout << u << " " << v << " " << del_u << " " << del_v << endl; if (!vis[v] && check(u,v)) dfs(v,u); } } void main() { memset(ans,0x3f,sizeof(ans)); memset(vis,0,sizeof(vis)); for (int i=1;i<=n;i++) sort(G[i].begin(),G[i].end()); for (int i=1;i<=m;i++) { cnt=0; memset(res,0,sizeof(res)); memset(vis,0,sizeof(vis)); del_u=edge[i][0]; del_v=edge[i][1]; dfs(1,0); /* for (int i=1;i<=n;i++) cout << res[i] << " "; cout << cnt << endl; */ if (comp() && cnt==n) memcpy(ans,res,sizeof(res)); } for (int i=1;i<=n;i++) printf("%d ",ans[i]); } } int main() { n=read(),m=read(); for (int i=1;i<=m;i++) { int u=read(),v=read(); G[u].push_back(v); G[v].push_back(u); edge[i][0]=u; edge[i][1]=v; } if (m==n-1) solve1::main(); else solve2::main(); return 0; } ``` 然后这份代码在不开O2的情况下是会tle的。(少爷机可能不会,手头上没有8700k)原因如下: 1、vector实在是太慢了,建议手写一个或者用链式前向星进行存图。 2、有很多无用的情况。无用的情况就是当删的这条边不在环上的时候,这样删去这条边,这个图就不连通了,可以直接剪枝。 如果在这上面进行好优化,码长++,时间--。 --- 不过还有一种很神仙的O(n)做法,好像是一边删一边维护什么的?不太会。 以及听说这个题目可以扩展到仙人掌上,甚至可以维护动态图连通性而扩展到dag上?

两个鬼故事一般建筑公司起名大全王会悟简介奇迹少女小鸠最新周易起名宝典查查起名吉凶测试打分公司起名字2021免费北京外墙保温梦到掉牙盐城热线广州市中小学教师继续教育网臭作动画下载qq金券安字取名男孩起名大全电视剧家有儿女高清电视直播软件属牛2009起名鬼FU全集无删减在线观看樱花动漫谁动了我的奶酪txt下载成了绝症男配的兔子精婴儿起名杨姓我们的法兰西岁月剧情介绍h文系列辣小说合集5721免费婴儿起名透视小邪医女宝洋气的起小名属牛的小朋友起名典字辈起名宠物店起名身上莫名其妙的起疙瘩司起名男孩三字少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

两个鬼故事 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化