洛谷传送门
BZOJ传送门
题目描述
最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。
Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。
现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有 N N N个路 口, M M M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
输入输出格式
输入格式:
第一行:两个整数 N N N和 M M M(含义如题目描述)。
第二行:四个整数 x 1 x_1 x1、 y 1 y_1 y1、 x 2 x_2 x2、 y 2 y_2 y2( 1 ≤ x 1 ≤ N 1 ≤ x_1 ≤ N 1≤x1≤N, 1 ≤ y 1 ≤ N 1 ≤ y_1 ≤ N 1≤y1≤N, 1 ≤ x 2 ≤ N 1 ≤ x_2 ≤ N 1≤x2≤N, 1 ≤ y 2 ≤ N 1 ≤ y_2 ≤ N 1≤y2≤N),分别表示Elaxia的宿舍和实验室及w**的宿舍和实验室的标号(两对点分别 x 1 , y 1 x_1,y_1 x1,y1和 x 2 , y 2 x_2,y_2 x2,y2)。
接下来 M M M行:每行三个整数, u u u、 v v v、 l l l( 1 ≤ u ≤ N 1 ≤ u ≤ N 1≤u≤N, 1 ≤ v ≤ N 1 ≤ v ≤ N 1≤v≤N, 1 ≤ l ≤ 10000 1 ≤ l ≤ 10000 1≤l≤10000),表 u u u和 v v v之间有一条路,经过这条路所需要的时间为 l l 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 ≤ 100 N ≤ 100 N≤100;
对于60%的数据, N ≤ 1000 N ≤ 1000 N≤1000;
对于100%的数据, N ≤ 1500 N ≤ 1500 N≤1500,输入数据保证没有重边和自环。
解题分析
做4遍 S P F A SPFA SPFA或 D i j k s t r a Dijkstra Dijkstra,求出四个点的单源最短路径, 进而得到最短路 D A G DAG DAG上的公共边, 最后按从 x 1 x_1 x1出发的最短路 D A G DAG DAG的拓扑序 d p dp dp得到答案。
注意在 x 1 → y 1 x_1\to y_1 x1→y1的最短路上可能有 y 2 → x 2 y_2\to x_2 y2→x2的一截最短路, 判断的时候应该小心。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <queue>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 1505
#define ME 200500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int dot, line, cnt, xx1, xx2, yy1, yy2;
bool inq[MX];
std::queue <int> q;
int st1[MX], ed1[MX], st2[MX], ed2[MX], head[MX], nw[MX], deg[MX];
struct Edge {int from, to, len, val, nex;} edge[ME << 2];
IN void add(R int from, R int to, R int len)
{edge[++cnt] = {from, to, len, 0, head[from]}, head[from] = cnt;}
IN void addnw(R int from, R int to, R int len, R int mul)
{edge[++cnt] = {from, to, len, mul, nw[from]}, nw[from] = cnt;}
IN int SPFA(int *dis, R int st)
{
std::memset(dis, 63, 4 * MX - 4);
dis[st] = 0; q.push(st); R int now, i;
W (!q.empty())
{
now = q.front(); q.pop();
for (i = head[now]; i; i = edge[i].nex)
{
if(dis[edge[i].to] > dis[now] + edge[i].len)
{
dis[edge[i].to] = dis[now] + edge[i].len;
if (!inq[edge[i].to]) inq[edge[i].to] = true, q.push(edge[i].to);
}
}
inq[now] = false;
}
}
void init()
{
int tmp = cnt;
for (R int i = 1; i <= tmp; ++i)
{
if(st1[edge[i].from] + edge[i].len + ed1[edge[i].to] == st1[yy1])//on the fisrt
{
if(st2[edge[i].from] + edge[i].len + ed2[edge[i].to] == st2[yy2] || st2[edge[i].to] + edge[i].len + ed2[edge[i].from] == ed2[xx2])
addnw(edge[i].from, edge[i].to, edge[i].len, 1);
else addnw(edge[i].from, edge[i].to, edge[i].len, 0);
++deg[edge[i].to];
}
}
}
IN void SPFA2(int *dis, R int st)
{
std::memset(dis, -1, MX * 4 - 4); dis[xx1] = 0;
q.push(xx1); R int now, i;
W (!q.empty())
{
now = q.front(); q.pop();
for (i = nw[now]; i; i = edge[i].nex)
{
if(!(--deg[edge[i].to])) q.push(edge[i].to);
dis[edge[i].to] = std::max(dis[edge[i].to], dis[now] + edge[i].len * edge[i].val);
}
}
}
int main(void)
{
int a, b, c;
in(dot), in(line), in(xx1), in(yy1), in(xx2), in(yy2);
for (R int i = 1; i <= line; ++i)
{
in(a), in(b), in(c);
add(a, b, c), add(b, a, c);
}
SPFA(st1, xx1); SPFA(ed1, yy1); SPFA(st2, xx2); SPFA(ed2, yy2);
init(); SPFA2(st1, xx1);
printf("%d", st1[yy1]);
}