Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)
题意
题目描述
最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的时间。
\(Elaxia\)和\(w**\)每天都要奔波于宿舍和实验室之间,他们希望在节约时间的前提下,一起走的时间尽可能的长。
现在已知的是\(Elaxia\)和\(w**\)所在的宿舍和实验室的编号以及学校的地图:地图上有\(N\)个路口,\(M\)条路,经过每条路都需要一定的时间。具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
输入输出格式
输入格式:
第一行:两个整数\(N\)和\(M\)(含义如题目描述)。
第二行:四个整数\(x_1,y_1,x_2,y_2(1\leq x_1 \leq N,1\leq y_1\leq N,1\leq x_2\leq N,1\leq y_2\leq N)\),分别表示\(Elaxia\)的宿舍和实验室及\(w**\)的宿舍和实验室的标号(两对点分别\(x1,y1\)和\(x2,y2\))。
接下来\(M\)行:每行三个整数,\(u,v,l(1\leq u\leq N,1\leq v\leq N,1\leq l\leq 10000)\),表示\(u\)和\(v\)之间有一条路,经过这条路所需要的时间为\(l\)。
输出格式:
一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)
输入输出样例
输入样例#1:
9 10
1 6 7 8
1 2 1
2 5 2
2 3 3
3 4 2
3 9 5
4 5 3
4 6 4
4 7 2
5 8 1
7 9 1
输出样例#1:
3
说明
对于\(30\%\)的数据,\(N\leq 100\);
对于\(60\%\)的数据,\(N\leq 1000\);
对于\(100\%\)的数据,\(N\leq 1500\),输入数据保证没有重边和自环。
思路
等我再调一下,我只有一个小错误了... --alecli
首先想想题目要求我们做什么。我们要求两组点对之间的最短路,每组点对之间的最短路可能有很多条。然后我们在每组点对中各选出一条最短路,使得它们之间的公共边的长度之和最长,并输出这个长度。
那么我们的算法流程就是:
- 找出第一组点对之间的所有最短路径。
- 找出第二组点对之间的所有最短路径。
- \(dfs\)选两条路径,计算公共边长度。
选出路径的复杂度已经很高了,再去计算公共边长度,时间就爆炸了。能不能优化一下呢?我们不妨这样写:
- 找出第一组点对之间的所有最短路径。
- 把这些最短路径经过的边都打上标记。
- 找出第二组点对之间的所有最短路径。
- 把这些最短路径经过的边都打上标记。
- 求被打上两次标记的边的边权之和。
这样会快很多,不过这又是显然有问题的,因为会有边的边权因为出现在多条最短路径中而被重复计算,所以我们不得不牺牲一些时间复杂度,这样改写:
- 找出第一组点对之间的所有最短路径。
- 把这些最短路径经过的边都打上标记。
- 找出第二组点对之间的所有最短路径。
- \(dfs\)求出一条第二组点对之间的最短路径,使得这条路径中已打上标记的路径的边权之和最大。
嘿,我们把\(TLE\)的做法和\(WA\)的做法综合在一起,就得出了\(AC\)的做法!得出结论(雾):
\]
另外,还有一些小的优化,比如在操作\(2\)中打标记,我们可以利用\(dfs\),从起点开始找到一条能到达终点的最短路径,然后把边全部打上标记。我们可以用记忆化来优化这一部分的时间。设变量\(to_t[i]\)表示是否存在一条经过\(i\)的从\(x_1\)到\(y_1\)的最短路。若\(to_t[i]=1\),则有;若\(to_t[i]=-1\),则无;若\(to_t[i]=0\),则表示我们还不知道有没有,接着搜索下去才能得到答案:
int dfs1(int u)
{
if(u==t1) return true;//到达终点
to_t[u]=-1;
for(int i=top[u];i;i=nex[i])
if(dis[to[i]]==dis[u]+len[i])//判断是否是最短路
{
if(to_t[to[i]]==-1) continue;//走不到终点,溜了
else if(to_t[to[i]]==1||dfs1(to[i])==1)//走得到或者搜索得到
{
to_t[u]=1;
G[u][to[i]]=G[to[i]][u]=len[i];//G数组存被标记上的边权
}
}
return to_t[u];
}
操作\(4\)中第二次\(dfs\)求答案时我们就可以暴力一点,顺着跑就好了。当然,优化方式也有很多,在这里就不举例了。
//ans[i]记录从起点到i点所能经过的最大被标记边权之和
void dfs2(int u)
{
for(int i=top[u];i;i=nex[i])
if(dis[to[i]]==dis[u]+len[i]&&ans[to[i]]<G[u][to[i]]+ans[u])//是最短路且对答案有贡献
{
ans[to[i]]=G[u][to[i]]+ans[u];//做记录
dfs2(to[i]);//往下搜索
}
}
AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1505;
int n,m,s1,t1,s2,t2,dis[MAXN],ans[MAXN],G[MAXN][MAXN],to_t[MAXN];
int cnt,top[MAXN],to[MAXN*MAXN],len[MAXN*MAXN],nex[MAXN*MAXN];
bool vis[MAXN];
int read()
{
int re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void SPFA(int s)
{
memset(dis,0x3f,sizeof dis);
dis[s]=0;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int now=Q.front();Q.pop();
vis[now]=false;
for(int i=top[now];i;i=nex[i])
if(dis[to[i]]>dis[now]+len[i])
{
dis[to[i]]=dis[now]+len[i];
if(!vis[to[i]])
{
vis[to[i]]=true;
Q.push(to[i]);
}
}
}
}
int dfs1(int u)
{
if(u==t1) return true;
to_t[u]=-1;
for(int i=top[u];i;i=nex[i])
if(dis[to[i]]==dis[u]+len[i])
{
if(to_t[to[i]]==-1) continue;
else if(to_t[to[i]]==1||dfs1(to[i])==1)
{
to_t[u]=1;
G[u][to[i]]=G[to[i]][u]=len[i];
}
}
return to_t[u];
}
void dfs2(int u)
{
for(int i=top[u];i;i=nex[i])
if(dis[to[i]]==dis[u]+len[i]&&ans[to[i]]<G[u][to[i]]+ans[u])
{
ans[to[i]]=G[u][to[i]]+ans[u];
dfs2(to[i]);
}
}
int main()
{
n=read(),m=read(),s1=read(),t1=read(),s2=read(),t2=read();
while(m--)
{
int x=read(),y=read(),z=read();
to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,len[cnt]=z,nex[cnt]=top[y],top[y]=cnt;
}
SPFA(s1);
if(dfs1(s1)==-1)
{
printf("0");
return 0;
}
SPFA(s2);
memset(ans,-1,sizeof ans);
ans[s2]=0;
dfs2(s2);
printf("%d",ans[t2]);
return 0;
}
Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)的更多相关文章
- Luogu P2149 [SDOI2009]Elaxia的路线 | 图论
题目链接 题解: 题面中给了最简洁清晰的题目描述:"求无向图中,两对点间最短路的最长公共路径". 对于这个问题我们可以先考虑图中的哪些边对这两对点的最短路产生了贡献. 比如说下面这 ...
- 洛谷 P2149 [SDOI2009]Elaxia的路线 解题报告
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia ...
- 洛谷——P2149 [SDOI2009]Elaxia的路线
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间.Elaxia和w每 ...
- BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )
找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...
- 【BZOJ1880】[SDOI2009]Elaxia的路线 (最短路+拓扑排序)
[SDOI2009]Elaxia的路线 题目描述 最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. \(El ...
- 【BZOJ1880】[Sdoi2009]Elaxia的路线 最短路+DP
[BZOJ1880][Sdoi2009]Elaxia的路线 Description 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起 ...
- Luogu P3953 逛公园(最短路+记忆化搜索)
P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...
- UVA - 10917 - Walk Through the Forest(最短路+记忆化搜索)
Problem UVA - 10917 - Walk Through the Forest Time Limit: 3000 mSec Problem Description Jimmy exp ...
- Luogu 3953[NOIP2017] 逛公园 堆优化dijkstra + 记忆化搜索
题解 首先肯定是要求出单源最短路的,我用了堆优化dijikstra ,复杂度 mlogm,值得拥有!(只不过我在定义优先队列时把greater 打成了 less调了好久 然后我们就求出了$i$到源点的 ...
随机推荐
- CSIC_716_20191114【生成器、匿名函数、内置函数、三元表达式、列表生成式、生成器表达式】
生成器: 函数与yield连用,凡是函数中有yield的,调用该函数的时候均不会立即执行,而是会返回一个生成器. 生成器本质上是一个迭代器,需要通过 [生成器.__next__()]或者[nex ...
- 挂载U盘
.fdisk -l 查看当前系统存储盘 (sdaX一般是系统自带, sdbX则是外接) .mount /dev/sdbX /mnt/usb/ (如果usb目录不存在可创建新目录) .umount /m ...
- day33 序列类型,绑定方法,类方法,静态方法,封装继承和多态
Python之路,Day20 = 序列类型,绑定方法,类方法,静态方法,封装继承和多态 序列是指有序的队列,重点在"有序". 一.Python中序列的分类 Python中的序列主要 ...
- 大数据之hadoop集群安全模式
集群安全模式1.概述(1)NameNode启动 NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作.-旦在内存中成功建立文件系统元数据的影像,则 ...
- react 16更新
1.render新的返回类型 render方法支持两种新的返回类型:数组(由React元素组成)和字符串 2.错误处理 16之前,组件在运行期间如果执行出错,就会阻塞整个应用的渲染,这时候只能刷新页面 ...
- eclipse配置外部工具利用javah编译生成头文件
1. 点击eclipse工具栏外部工具按钮,打开配置外部工具 2. 新建一个启动配置,起名为Generate C and C++ Header File,按照下图配置好相应的参数 3. 运行该工具时, ...
- Delphi编写后台监控软件
Delphi编写后台监控软件 文章来源:Delphi程序员之家 后台监控软件,为了达到隐蔽监控的目的,应该满足正常运行时,不显示在任务栏上,在按Ctrl+Alt+Del出现的任 ...
- jQuery WeUI
jQuery WeUI jQuery WeUI 是专为微信公众账号开发而设计的一个简洁而强大的UI库,包含全部WeUI官方的CSS组件,并且额外提供了大量的拓展组件,丰富的组件库可以极大减少前端开发时 ...
- Laravel依赖
首先有个接口 interface Visit { public function go (); } 然后有三个类Leg,Car,Train class Leg implements Visit { p ...
- 重写、super关键字、final关键字、多态、子类型转换、抽象的初步了解
重写 含义 在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法.但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写.方法重写又称方法覆盖. 重写与重载的 ...