P2149 [SDOI2009]Elaxia的路线[最长公共路径]
题目描述
最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。
Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。
现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
解析
这个题,怎么说呢,对我来说思维难度还是比较低的,但是代码难度稍微就高了点。
题目清楚的告诉我们要求两对点之间最短路的最大公共路径。实际上两点之间的最短路可能有多条,于是我们就要把它们都标出来。题目还提到希望在节约时间的前提下,一起走的时间尽可能的长,因此我们并不一定需要两人都只走各自的最短路,我们只需要让最终答案最优即可(即不能再更节约时间,一起走的时间不能再更长)。为了更好表示,我们引入一些符号。
设\(x1,y1\)之间所有最短路的边的集合为\(A\),\(x2,y2\)之间所有最短路的边的集合为\(B\)。我们首先要做的是找出这两个集合,然后比对\(A\)和\(B\),找出一个集合\(C\in A \cap B\),它就是两点对所有最短路径的公共边。
此时,我们只需要在\(C\)中找出一条最长的简单路径即可。为什么是简单路径呢,因为最短路本身就是简单路径嘛(废话)。
首先标记最短路上的边很容易,我们分别从起点终点两端点跑两遍最短路算法,然后再对每条边进行检查。假设起点为\(s\),终点为\(t\),对于某个点\(x\),它扩展出的点为\(y\),它们之间的边\(c(x,y)=z\),\(d[x]\)为到\(x\)点的最短路,如果有\(d[x]+d'[y]+z=d[t]\),那么这条边在\(s\rightarrow t\)最短路上。所以两对点我们要跑四次。注意,如果我们不跑两遍最短路的话,该方法会标记所有可达边。
所以接下来怎么找\(C\)中的最长简单路径呢?说实话我没想出来。
一开始打算在第二轮最短路时搞一个类似递推的东西统计。显然对于某个点\(y\),它可以由很多个点扩展而来,而我们只选取其中使得最长公共路径最大的一个点\(x\)扩展过来(当然首先这条边\(c(x,y)\)得在\(C\)中)。然而本人能力实在有限,并没有没码出来(就是菜)。看到题解里似乎也有人这么写,并且过了,我枯了。
遂看了题解,震惊,竟然可以用拓扑排序?!(我才不写什么狗屁重载呢,麻烦的很)
我还在纳闷无向图怎么搞拓扑的时候,人家已经想到分析两人同方向走和反方向走两种情况了!意思就是说我们可以考虑两人同方向和反方向走两种情况的最长公共路径,妙哉!
因此我们需要对两张图进行拓扑排序找最长链:\(x1\rightarrow y1\)所有最短路上的边按照\(x1\rightarrow y1\)的方向存,\(x2\rightarrow y2\)的所有最短路上的边按照\(x2\rightarrow y2\)的方向存的图1;\(x1\rightarrow y1\)所有最短路上的边按照\(x1\rightarrow y1\)的方向存,\(y2\rightarrow x2\)的所有最短路上的边按照\(y2\rightarrow x2\)的方向存的图2,注意这些最短路边包含在\(C\)中。
最后在两张图的最优解中择优。
神奇。
参考代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 3010
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct rec{
int next,ver,edge;
}g[N*N],G[N*N];
int head[N],tot,headG[N],totG,n,m,x1,x2,y1,y2;
int d[4][N],ing[N],c[N];
bool v[N];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
inline void add(int x,int y,int val)
{
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
}
inline void addG(int x,int y,int val)
{
G[++totG].ver=y,G[totG].edge=val;
G[totG].next=headG[x],headG[x]=totG;
ing[y]++;
}
inline void dijkstra(int k,int x)
{
memset(d[k],0x3f,sizeof(d[k]));
memset(v,0,sizeof(v));
d[k][x]=0;q.push(make_pair(0,x));
while(q.size()){
int index=q.top().second;q.pop();
if(v[index]) continue;
v[index]=1;
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(d[k][y]>d[k][index]+z){
d[k][y]=d[k][index]+z;
q.push(make_pair(d[k][y],y));
}
}
}
}
inline void sign(int k)
{
for(int i=1;i<=n;++i)
for(int j=head[i];j;j=g[j].next){
int y=g[j].ver,z=g[j].edge;
if(d[0][i]+z+d[2][y]==d[0][y1]&&d[1][i]+z+d[3][y]==d[1][y2]&&k==1)
addG(i,y,z);
if(d[0][i]+z+d[2][y]==d[0][y1]&&d[3][i]+z+d[1][y]==d[1][y2]&&k==2)
addG(i,y,z);
}
}
int main()
{
n=read(),m=read();
x1=read(),y1=read(),x2=read(),y2=read();
for(int i=1;i<=m;++i){
int u,v,val;
u=read(),v=read(),val=read();
add(u,v,val),add(v,u,val);
}
dijkstra(0,x1),dijkstra(1,x2);
dijkstra(2,y1),dijkstra(3,y2);
//topsort
int ans=0;
queue<int> Q;
sign(1);
for(int i=1;i<=n;++i)
if(ing[i]==0) Q.push(i);
while(Q.size()){
int x=Q.front();Q.pop();
for(int i=headG[x];i;i=G[i].next){
int y=G[i].ver,z=G[i].edge;
if(--ing[y]==0){
c[y]=max(c[x]+z,c[y]);
ans=max(ans,c[y]);
Q.push(y);
}
}
}
memset(ing,0,sizeof(ing));
memset(headG,0,sizeof(headG));
memset(c,0,sizeof(c));
sign(2);
for(int i=1;i<=n;++i)
if(ing[i]==0) Q.push(i);
while(Q.size()){
int x=Q.front();Q.pop();
for(int i=headG[x];i;i=G[i].next){
int y=G[i].ver,z=G[i].edge;
if(--ing[y]==0){
c[y]=max(c[x]+z,c[y]);
ans=max(ans,c[y]);
Q.push(y);
}
}
}
cout<<ans<<endl;
return 0;
}
P2149 [SDOI2009]Elaxia的路线[最长公共路径]的更多相关文章
- 洛谷 P2149 [SDOI2009]Elaxia的路线 解题报告
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia ...
- 洛谷——P2149 [SDOI2009]Elaxia的路线
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间.Elaxia和w每 ...
- Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)
P2149 [SDOI2009]Elaxia的路线 题意 题目描述 最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的 ...
- P2149 [SDOI2009]Elaxia的路线
题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在 ...
- 洛谷 P2149 [SDOI2009]Elaxia的路线
题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间.Elaxia和w每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的 ...
- 洛谷—— P2149 [SDOI2009]Elaxia的路线
https://www.luogu.org/problem/show?pid=2149 题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两 ...
- Luogu P2149 [SDOI2009]Elaxia的路线 | 图论
题目链接 题解: 题面中给了最简洁清晰的题目描述:"求无向图中,两对点间最短路的最长公共路径". 对于这个问题我们可以先考虑图中的哪些边对这两对点的最短路产生了贡献. 比如说下面这 ...
- bzoj1880: [Sdoi2009]Elaxia的路线(spfa,拓扑排序最长路)
1880: [Sdoi2009]Elaxia的路线 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1944 Solved: 759[Submit][St ...
- Spfa+DP【p2149】[SDOI2009]Elaxia的路线
Description 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia和w**每天都要奔波于宿舍和实验室之间 ...
随机推荐
- 【Python学习之四】集合类型
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 python3.6 一.字符串:字符串实际上就是字符的数组1.切片是指 ...
- 【视频开发】【Live555】通过live555实现H264 RTSP直播
前面的文章中介绍了<H264视频通过RTMP流直播>,下面将介绍一下如何将H264实时视频通过RTSP直播. 实现思路是将视频流发送给live555, 由live555来实现H264数据流 ...
- Linux04 目录的相关操作(mkdir、rmdir、rm、cp)
一.创建目录:mkdir mkdir 目录名 二.删除目录:rmdir / rm rmdir 目录名 rm -r 目录名 每一级子目录都会询问是否删除 rm -rf 目录名 慎用,给 ...
- JZOJ
题目: 三类动物A.B.C,A吃B,B吃C,C吃A.给出K句话来描述N个动物(各属于A.B.C三类之一)之间的关系,格式及意义如下:1 X Y:表示X与Y是同类: 2 X Y:表示X吃Y.K句话中有真 ...
- python三大器之装饰器的练习
装饰器 加载顺序从下至上 执行顺序从上至下 ''' 多层装饰器 ''' def deco1(func): #func=deco2 def wrapper1(*args, **kwargs): '''t ...
- Fedora30 install VS Code
We currently ship the stable 64-bit VS Code in a yum repository, the following script will install t ...
- python函数知识七 闭包、装饰器一(入门)、装饰器二(进阶)
21.闭包 闭包:在嵌套函数内,使用非全局变量(且不使用本层变量) 闭包的作用:1.保证数据的安全性(纯洁度).2.装饰器使用 .__closure__判断是否是闭包 def func(): a = ...
- Mybatis @One注解使用
@One注解:一对一关联查询
- python3与Excel的完美结合
https://segmentfault.com/a/1190000016256490 Excel 是 Windows 环境下流行的.强大的电子表格应用.openpyxl 模块让 Python 程序能 ...
- jmeter_分布式测试
背景: 由于Jmeter本身的瓶颈,当需要模拟数以千计的并发用户时,使用单台机器模拟所有的并发用户就有些力不从心,甚至还会引起JAVA内存溢出的错误.要解决这个问题,可以使用分布式实测 ...