Luogu P2149 [SDOI2009]Elaxia的路线 | 图论
题解:
题面中给了最简洁清晰的题目描述:“求无向图中,两对点间最短路的最长公共路径”。
对于这个问题我们可以先考虑图中的哪些边对这两对点的最短路产生了贡献。
比如说下面这个图:
我们要求从1到8的最短路和从3到5的最短路的最长公共路径。
先考虑有哪些边对从1到8的最短路产生了贡献,并按这些边被经过时的方向构造一个有向图。
如下:
然后再考虑有哪些边对从3到5的最短路产生了贡献,然后也按这些边被经过时的方向构造一个有向图。
如下:
我们知道,这两对点间最短路的最长公共路径一定在上述两张有向图的重叠部分中。
于是我们可以试着将那两张有向图重叠起来:
接着提取其中的公共部分:
由于我们一开始构造的两张图都一定是有向无环图(想想为什么),所以它们的公共部分也一定是若干张有向无环图。
又因为两点间的最短路一定是一条链,所以两条最短路的公共部分也一定是一条链。
这样的话,我们的任务就变成了在这若干张有向无环图中求最长链。
这个问题可以用dp在O(n)的时间内解决。
那么如何我们该如何构造一开始的两张有向图呢?这可以用SPFA解决。
对于每个点,都记录它是从哪个点走过来的,最后从终点倒推回去即可。
值得注意的是,我们不能只对其中一对点的一个点构造有向图。因为在最短路上走的方向可能是不同的,如果只构造一张图的话就会漏掉行走方向不同的边。
像上面我们举的那个例子,这条边就没有被算进去,但它其实也是这两对点间最短路的公共部分。
那么我们能不能直接忽略图的方向呢?
不行,因为如果直接忽略图的方向的话,我们得出来的答案可能会属于一对点之间的两条不同的最短路(想想为什么)。
对此,我们可以对其中一对点的最短路正着构造出一个有向图,反着再构造出一个有向图,然后将它们分别与对另一对点的最短路构造的有向图进行相应的操作即可。
比如说上面所举的那个例子,我们先对结点1到结点8的最短路构造一个有向图(称为图1),然后再分别对结点3到结点5的最短路和结点5到结点3的最短路构造一个有向图(分别称为图2和图3)。最后,我们先拿图1和图2做一次那样的操作,然后再拿图1和图3做一次那样的操作即可。(“那样的操作”是指提取公共部分和dp求最长链。)
总时间复杂度为O(nm+n2+n),其中的nm是SPFA在最坏情况下的时间复杂度,n2是提取两张有向图公共部分的时间复杂度,n是dp求最长链的时间复杂度。
这个时间复杂度虽然理论上来说是不能过的,但在实际测试中,SPFA的时间复杂度是低于O(nm)的上限的,所以这是能过的。
大家也可以用使用堆优化的dijkstra算法来代替SPFA,以换取在求最短路时O(nlog2n)的稳定时间复杂度。
提取两张有向图公共部分的时间其实也是可以优化的,但这个实现起来较为简单,就不再赘述了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n=0,m=0,x1=0,y1=0,x2=0,y2=0,ans=0,head=0,tail=0;
//last[i][j]=1表示编号为i的结点可以从编号为j的结点走过来
int d[1505],k[1505],dis[1505],book[1505],que[2265025],last[1505][1505],f[1505][1505],s[1505][1505],h[1505][1505],p[1505][1505];
void SPFA(int s)//SPFA
{
head=1,tail=0;
for(int i=1;i<=n;i++) dis[i]=1e8,book[i]=k[i]=0;
dis[s]=0;
que[++tail]=s;
book[s]=1;
while(head<=tail)
{
int u=que[head++];
book[u]=false;
for(int i=1;i<=n;i++)
{
if(i==u) continue;
if(dis[u]+f[u][i]<dis[i])
{
dis[i]=dis[u]+f[u][i];
k[i]=1;
last[i][k[i]]=u;//更新last数组
if(book[i]==false)
{
que[++tail]=i;
book[i]=true;
}
}
else if(dis[u]+f[u][i]==dis[i]) last[i][++k[i]]=u;//更新last数组
}
}
}
void work(int x,int h[][1505])//构造对最短路有贡献的边所组成的有向图
{
if(book[x]==1) return;
book[x]=1;
for(int i=1;i<=k[x];i++)
{
h[last[x][i]][x]=1;
work(last[x][i],h);
}
}
void dp(int x)//dp求有向无环图最长链
{
if(d[x]>0) return;
for(int i=1;i<=n;i++)
if(p[x][i]==1)
{
dp(i);
d[x]=max(d[x],d[i]+f[x][i]);
}
}
int main()
{
scanf("%d%d%d%d%d%d",&n,&m,&x1,&y1,&x2,&y2);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=(i==j)?0:1e8;
for(int i=1;i<=m;i++)
{
int u=0,v=0,w=0;
scanf("%d%d%d",&u,&v,&w);
f[u][v]=f[v][u]=min(f[u][v],w);//邻接矩阵存图
}
//对从x1到y1的最短路进行处理
SPFA(x1);
memset(s,0,sizeof(s));
memset(book,0,sizeof(book));
work(y1,s);
//对从x2到y2的最短路进行处理
SPFA(x2);
memset(h,0,sizeof(h));
memset(book,0,sizeof(book));
work(y2,h);
//提取两张有向图的公共部分
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(s[i][j]==1&&h[i][j]==1) p[i][j]=1;
else p[i][j]=0;
//dp求最长链
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
if(d[i]==0) dp(i);
for(int i=1;i<=n;i++) ans=max(ans,d[i]);
//对从y2到x2的最短路进行处理
SPFA(y2);
memset(h,0,sizeof(h));
memset(book,0,sizeof(book));
work(x2,h);
//提取两张有向图公共部分
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(s[i][j]==1&&h[i][j]==1) p[i][j]=1;
else p[i][j]=0;
//dp求最长链
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
if(d[i]==0) dp(i);
for(int i=1;i<=n;i++) ans=max(ans,d[i]);
//输出
printf("%d",ans);
return 0;
}
Luogu P2149 [SDOI2009]Elaxia的路线 | 图论的更多相关文章
- Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)
P2149 [SDOI2009]Elaxia的路线 题意 题目描述 最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的 ...
- 洛谷 P2149 [SDOI2009]Elaxia的路线 解题报告
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia ...
- 洛谷——P2149 [SDOI2009]Elaxia的路线
P2149 [SDOI2009]Elaxia的路线 题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间.Elaxia和w每 ...
- 洛谷—— P2149 [SDOI2009]Elaxia的路线
https://www.luogu.org/problem/show?pid=2149 题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两 ...
- P2149 [SDOI2009]Elaxia的路线
题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在 ...
- 洛谷 P2149 [SDOI2009]Elaxia的路线
题目描述 最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间.Elaxia和w每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的 ...
- P2149 [SDOI2009]Elaxia的路线[最长公共路径]
题目描述 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在 ...
- Luogu 2149 [SDOI2009]Elaxia的路线
感觉这题可以模板化. 听说spfa死了,所以要练堆优化dijkstra. 首先对$x_{1},y_{1},x_{2},y_{2}$各跑一遍最短路,然后扫一遍所有边看看是不是同时在两个点的最短路里面,如 ...
- BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )
找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...
随机推荐
- css3 横屏
@media screen and (orientation: portrait) { html{ width : 100vmin; height : 100vmax; } body{ width : ...
- C# 获取动态类中所有的字段
/// <summary> /// 动态类 获取字典集合 /// </summary> /// <typeparam name= ...
- javascript 自定义事件 发布-订阅 模式 Event
* javascript自定义事件 var myEvent = document.createEvent("Event"); myEvent.initEvent("myE ...
- 对OOP的理解
OOP是面向对象编程Object Oriented Programming,特征分别是封装.继承.多态.抽象. 封装:封装是指将对象信息状态通过访问权限修饰符隐藏在对象内部,不允许外部程序直接访问,如 ...
- Python - Context Manager 上下文管理器
什么是上下文管理器 官方解释... 上下文管理器是一个对象 它定义了在执行 with 语句时要建立的运行时上下文 上下文管理器处理进入和退出所需的运行时上下文以执行代码块 上下文管理器通常使用 wit ...
- Orchard Core 配置项说明
Orchard Core使用IShellConfiguration扩展了ASP.NET Core IConfiguration,以允许在应用程序范围的配置之上进行特定于租户的配置.虽然本文档使用Orc ...
- CF453C-Little Pony and Summer Sun Celebration【构造】
正题 题目链接:https://www.luogu.com.cn/problem/CF453C 题目大意 \(n\)个点\(m\)条边的一张无向图,每个节点有一个\(w_i\)表示该点需要经过奇数/偶 ...
- Python3入门系列之-----看完这一篇文章我终于学会了类
前言 类顾名思义,就是一类事物.或者叫做实例,它用来描述具有共同特征的一类事物.我们在Python中声明类的关键词是class,类还有功能和属性,属性就是这类事物的特征,而功能就是它能做什么,也是就是 ...
- IP多播与NAT地址转化
IP多播 与单播相比,在一对多的通信中,多播可以大大减少网络资源.在互联网上进行多播就叫做IP多播,IP多播所传送的分组需要使用IP多播地址. 如果某台主机想要收到某个特定的多播分组,那么怎样才能是这 ...
- 【C++ Primer Plus】编程练习答案——第7章
1 double ch7_1_harmonicaverage(double a, double b) { 2 return 2 / (1 / a + 1 / b); 3 } 4 5 void ch7_ ...