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**每天都要奔波于宿舍和实验室之间 ...
随机推荐
- MySQL之表关系
MySQL表关系 一对多关系 一对多与多对一是一个概念,指的是一个实体的某个数据与另外一个实体的多个数据有关联关系. 举例,学校中一个学.院可以有很多的学生,而一个学生只属于某一个学院(通常情况下), ...
- c# Aspose.Cells 通过Excel模板生产excel数据再打印
多的不说,我们先来利用Northwind做两个小demo.先说说Aspose.Cells的模板语法: &=DataSource.Field,&=[DataSource].[Field] ...
- jquery json对象转换
jquery json对象转换 <pre>//json数组转json串var arr = [1,2,3, { a : 1 } ];JSON.stringify( arr ); //json ...
- python 数据库导入excel
import MySQLdb import xlwt def outMySQL(file_name): wb = xlwt.Workbook() sh = wb.add_sheet('sheet 1' ...
- 第7/7Beta冲刺
1.团队成员 成员姓名 成员学号 秦裕航 201731062432(组长) 刘东 201731062227 张旭 201731062129 王伟 201731062214 2.SCRU部分 2.1各成 ...
- 树莓派raspberrypi系统安装docker以及编译nginx和php镜像
前言 在树莓派中搭建php环境,按正常流程一般是直接在系统中apt-get install相关的软件,不过如果某天我想无缝迁移到另一个地方,就又得在重新安装一次环境.所以为了方便,就直接在树莓派中使用 ...
- 自定义 Generate POJOs.groovy
一.Generate文件 import com.intellij.database.model.DasTable import com.intellij.database.model.ObjectKi ...
- .Net Core-类库中创建CodeFirst
本文仅用来学习记录. 搭建项目架构的时候,需要在类库中进行CodeFirst数据迁移 1.在项目的解决方案中,添加类库ERPFrame.Model 2.在类库项目中 添加实体模型和数据上下文 其中 ...
- 【洛谷 P5357】 【模板】AC自动机(二次加强版)(AC自动机,差分)
每次匹配都不停跳fail显然太慢了,于是在每个节点和fail指向的点连一条边,构成一棵树,在这棵树上差分一下就好了. AC自动机 就这个算法而言其实没用想象中那么难. #include <cst ...
- jmeter用什么查看结果报告
JMeter查看测试结果的方法很多,最常用的几种是:察看结果树.聚合报告.图形报表.邮件观察仪等.