洛谷 P5022 旅行
今天换标题格式了,因为感觉原版实在有点别扭……
还是直接上题板,看完题再讲吧:
对了有个小细节没说,m一定是等于n或者等于n-1的。
这题是2018年提高组的真题哦!被我肝了2天肝出来了,2天……(真打提高怕不是废了)
哎呀不说废话直接开始。首先我们知道m肯定等于n或者n-1,就可以把这个题分成2种情况:
先做第一种:好做的m等于n-1
在m等于n-1的情况,是不存在指针在里面转圈圈,转到一半还要退出来的情况的。至于这是为什么,我们可以把他看成是一个每个点的入度都为一的图,每个点只有一次从别的点来这个点(不算从别的点退回来)的机会(虽然有些数据看上去不是这样,但其实就是这样),所以我们只要先把输入点按从小到大排个序,然后用小猪佩奇和大家都喜欢用的邻接表存图,再把图遍历一遍就ok了。(起点肯定是1,字典序最小的序列一定是1开头的)
然后再做第二种:难做的m等于n
这种我用了链式前向星的哟~
什么?你说你不会链式前向星?想学习一下吗,请戳这里。
这一定不是我给自己打广告(大声bb)
在m等于n的情况下,一些邪恶的数据会让你在里面转圈圈,然后他的正解还是转到一半就停下。哎呀呀怎么办呢?我又不会高端算法……但我的老师告诉我,暴力出奇迹,偏分过样例。
但是做题得不了满分,你的程序还有什么用呢?我就算不做,noip提高爆零,也绝不会暴力的!
然后我就开始打模拟了(嗯真香),愉快的得了85分。然后我因为不会做看着题目发呆……(同学们别学我)然后我阴差阳错的又看了一遍数据表:
哎我的程序应该效率是O(n^2)多一点。n^2应该是25000000,应该里AC只差一点点了,只要加一点适度的优化。于是我重新审视了我的代码。
我之前的代码是纯洁的暴力,虽然道路有m条,但我们只需要m-1条,所以我们就暴力去掉一条没用的吧!真是个好主意!
然后暴力去掉一条没用的之后就开始纯洁暴力……现在就相当于m等于n-1的局势了,所以现在的操作和第一种一样,把图遍历一遍就ok了。
怎么样,是不是看起来没啥毛病(然鹅大佬早就看出了瑕疵)
桥豆麻袋,别急着提交,搜索里有个神奇的东西叫做最优化剪枝。
也就是说,如果我们之前找到了一个比这个方法更优的方法,那这个就完全没必要再试了!然后我们只要在每一位存进数组的时候检查一下是否符合要求,符合就加入,不符合直接丢掉……
就可以剩下很多时间啊!(这么好想我竟然没想到……而且还因为大小于号打反调试了2小时,zz体制再次实锤……)
于是我们A了。
好了好了,接下来就是代码讲解时间:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
long long t,w,ans,head[5005],zshu[5005],za[5005],ja,jb,zac;//head数组是链式前向星要用的,head[i]用来标记最后一个出发点为i的位置。 za是用来暂存新方案的数组
long long n,m;//想必不用解释
long long a,b;
long long zy[5005];//zy是最优方案。
long long fh=0;
struct hehe
{
long long t,w,syg;//t是头,w是尾,syg是上一个头为t的编号。(写完才发现t毛用没有)
}lsqxx[10005];//lsqxx,链式前向星的首字母
void add(long long t,long long w)
{
ans++;
lsqxx[ans].t=t;//这句话完全可以删掉
lsqxx[ans].w=w;
lsqxx[ans].syg=head[t];//这个的意思是保存上一个为t的编号。
head[t]=ans;//现在他自己就是上一个。
}
vector<long long>sz[5005];//排序用的(vector是真的香)
long long zhi,bj[5005];//bj是不要走回头路的标记
int px(long long a1,long long a2)
{
return a1<a2;//排序方法,学过sort的都知道
}
void dfs(long long z,long long f)//这里就是计算m等于n-1的情况的函数
{
if(bj[z]==1)//可行性剪枝
{
return;
}
bj[z]=1;
printf("%lld ",z);//肯定最小的。为什么?因为前面排过序了。
for(int i=0;i<sz[z].size();i++)
{
zhi=sz[z][i];
if(zhi==f)//继续可行性
{
continue;
}
dfs(zhi,z);//选定地点,继续出发
}
}
void dfs2(long long z,long long f)//这个就是m等于n的时候的函数
{
if(bj[z]==1)//随处可见的可行性剪枝
{
return;
}
bj[z]=1;
za[zac]=z;//候选新成员
if(za[zac]<zy[zac])//这个比之前的都小,就算以后再大,这个也是目前字典序最小的
{
fh=1;
}else if(za[zac]>zy[zac])//这个爆掉了~
{
if(fh==0)//彻底爆掉了~
{
return;
}
}
zac++;//下一个位置
for(int i=0;i<sz[z].size();i++)
{
zhi=sz[z][i];
if(zhi==f)
{
continue;
}
if((zhi==ja&&z==jb)||(zhi==jb&&z==ja))//ja和jb就是被禁止通行的2个端点编号
{
continue;
}
dfs2(zhi,z);
}
}
void zhuanyi()
{
for(int i=0;i<=n-1;i++)//最小序列,易主。
{
zy[i]=za[i];
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&a,&b);
sz[a].push_back(b);//在可通行列表里加上
sz[b].push_back(a);
add(a,b);
add(b,a);
}
for(int i=1;i<=n;i++)
{
sort(sz[i].begin(),sz[i].end(),px);//排序
}
if(m==n-1)
{
dfs(1,2147483647);//第一种情况,直接开始
return 0;
}else//恶心的第二种情况
{
for(int i=0;i<=n;i++)//开局重置(不知道为什么,用memset会爆掉,可能他不让设定太大的初始值)
{
zy[i]=2147483647;
}
for(int i=1;i<=ans;i+=2)//链式前向星的威力出现了(感觉好没用)
{
zac=0;//防止去掉了一个必须要经过的道路(就是长度不够)
fh=0;//这个是通过与否的标记
ja=lsqxx[i].t;//顶下2个不能互通的顶点
jb=lsqxx[i].w;//同上
memset(bj,0,sizeof(bj));//bj数组初始化
dfs2(1,2147483647);//开始尝试
if(zac<n)//emm失误了。
{
continue;
}
if(fh==1)//这个序列字典序比之前都小。
{
zhuanyi();//转移
}
}
for(int i=0;i<=n-1;i++)//字典序最小序列出炉
{
printf("%lld ",zy[i]);
}
}
return 0;
}
懒得讲解所以我就写成注释了
好了这篇博客就到这里。
对了这个代码只能过普通版,数据加强版是过不了的,各位渴望知识的同学们还是找别的大佬吧(大声的忠告)
洛谷 P5022 旅行的更多相关文章
- 洛谷 P5022 旅行——题解
发现大部分题解都是O(n^2)的复杂度,这里分享一个O(n)复杂度的方法. 题目传送 首先前60%的情况,图是一棵无根树,只要从1开始DFS,每次贪心走点的编号最小的点就行了.(为什么?因为当走到一个 ...
- 洛谷P5022 旅行 题解 去环/搜索
题目链接:https://www.luogu.org/problem/P5022 这道题目一开始看的时候没有思路,但是看到数据范围里面有一个: \(m = n-1\) 或 \(m = n\) ,一下子 ...
- 洛谷P5022 旅行 题解
前面几个代码都是部分分代码,最后一个才是AC了的,所以最后一个有详细注释 安利一发自己的Blog 这是提高组真题,233有点欧拉回路的感觉. 题目大意: 一个 连通 图,双向边 ,无重边 , 访问图中 ...
- 洛谷P5022&P5049 旅行(及其数据加强版)
旅行(不是加强版) 加强版 加强版数据范围: 我们注意到 也就是说要么是个树,要么是个基环树 60pts 这60分是个树,可以简单的贪心想到每次都走子树中编号最小的那个,并且把1作为根 dfs练手题 ...
- 洛谷 P1515 旅行
P1515 旅行 题目描述 你要进行一个行程为7000KM的旅行,现在沿途有些汽车旅馆,为了安全起见,每天晚上都不开车,住在汽车旅馆,你手里现在已经有一个旅馆列表,用离起点的距离来标识,如下: 0, ...
- 洛谷P1137 旅行计划
P1137 旅行计划 题目描述 小明要去一个国家旅游.这个国家有N个城市,编号为1-N,并且有M条道路连接着,小明准备从其中一个城市出发,并只往东走到城市i停止. 所以他就需要选择最先到达的城市,并制 ...
- 洛谷 P1137 旅行计划
旅行计划 待证明这样dp的正确性. #include <iostream> #include <cstdio> #include <cstring> #includ ...
- 洛谷 P1137 旅行计划 (拓扑排序+dp)
在DAG中,拓扑排序可以确定dp的顺序 把图的信息转化到一个拓扑序上 注意转移的时候要用边转移 这道题的dp是用刷表法 #include<bits/stdc++.h> #define RE ...
- 洛谷P1137 旅行计划 解题报告(拓扑排序+DP)
我看了一下其他大佬的题解,大部分都是拓扑排序加上DP.那么我想有的人是不明白为什么这么做的,拓扑排序有什么性质使得可以DP呢?下面我就提一下. 对一个有向无环图(Directed Acyclic Gr ...
随机推荐
- 研为电子6轴运动控制卡win10驱动无法安装问题,解决方法
研为电子6轴运动控制卡win10驱动无法安装问题,解决方法 研为电子6轴运动控制卡win10驱动无法安装问题,解决方法 iMC3xx2E系列运动控制卡使用手册V1.003 IMCdrv_Ins.exe ...
- 触发器_实现ORACEL自动增长字段
实现XX表的字段code,为自动增长字段? 1.创建一个sequence,如图: 输入如下数据: S_COUNTRY为sequence名称 2.创建一个触发器,目的是在插入数据之前插入自动增长的数字, ...
- JavaWeb网上图书商城完整项目-CommonUtils(1生成uuid,2Map转换成JavaBean)
java工程中添加上面的jar包 CommonUtils类就两个方法: l String uuid():生成长度32的随机字符,通常用来做实体类的ID.底层使用了UUID类完成: l T toBe ...
- 如何修改linux下tomcat指定的jdk路径
一般情况下,一台服务器只跑一个项目,只需根据所需项目,将linux默认的jdk环境配置好即可.某些时候一台服务器上会跑多个项目,而且各个项目需要的JDK版本各不相同,或者为了使业务独立开来,需要指定T ...
- C#数据结构与算法系列(十九):选择排序算法(SelectSort)
1.介绍 选择排序算法属于内部排序算法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置达到排序的目的 时间复杂度:O(n^2) 双层for 2.思想 选择排序(select sorti ...
- 洛谷 CF1012C Hills (动态规划)
题目大意:有n个山丘 , 可以在山丘上建房子 , 建房子的要求是 : 该山丘的左右山丘严格的矮于该山丘 (如果有的话),你有一架挖掘机,每单位时间可以给一个山丘挖一个单位的高度,问你想要建造 1,2, ...
- 文档翻译经验分享(Markdown)
该教程基于VSCode 加一些插件 youdao translate https://marketplace.visualstudio.com/items?itemName=Yao-Translate ...
- Nginx配置upstream实现负载均衡1
如果Nginx没有仅仅只能代理一台服务器的话,那它也不可能像今天这么火,Nginx可以配置代理多台服务器,当一台服务器宕机之后,仍能保持系统可用.具体配置过程如下: 1. 在http节点下,添加ups ...
- 生日聚会Party——这个线性dp有点嚣张
题目描述 今天是hidadz小朋友的生日,她邀请了许多朋友来参加她的生日party. hidadz带着朋友们来到花园中,打算 坐成一排玩游戏.为了游戏不至于无聊,就座的方案应满足如下条件:对于任意连续 ...
- expected single matching bean but found 2: menusServiceImpl,IMenusService
问题如下: 接口也作为匹配的bean? 有点迷惑了....... 经过在网上找资料,发现和@MapperScan这个注解有关系,具体源码不止.但是这个注解会扫描路径下的所有类. 去掉这个注解就可以正常 ...