BZOJ1880 [Sdoi2009]Elaxia的路线 【最短路 + dp】

题目

最近,Elaxia和w的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。Elaxia和w每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。 现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。

输入格式

第一行:两个整数N和M(含义如题目描述)。 第二行:四个整数x1、y1、x2、y2(1 ≤ x1 ≤ N,1 ≤ y1 ≤ N,1 ≤ x2 ≤ N,1 ≤ ≤ N),分别表示Elaxia的宿舍和实验室及w**的宿舍和实验室的标号(两对点分别 x1,y1和x2,y2)。 接下来M行:每行三个整数,u、v、l(1 ≤ u ≤ N,1 ≤ v ≤ N,1 ≤ l ≤ 10000),表 u和v之间有一条路,经过这条路所需要的时间为l。 出出出格格格式式式::: 一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)。

输出格式

一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)

输入样例

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

输出样例

3

提示

对于30%的数据,N ≤ 100;
对于60%的数据,N ≤ 1000;
对于100%的数据,N ≤ 1500,输入数据保证没有重边和自环。

题解

最后的路径为公共的最短路,所以我们先将第一对点的所有最短路边建成一个新的拓扑图
然后就可以在新图上dp了
\(f[i]\)为第一对点走到\(i\)时的最大公共最短路长
显然\(f[i] = max{f[j] + edge.w}\)\(j\)\(i\)拓扑图中的前驱点且i-j这条边在第二对点的最短路上】

#include<iostream>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 1505,maxm = 3000005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
	return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int from,to,nxt,w,f;}ed[maxm];
inline void build(int u,int v,int w){
	ed[ne] = (EDGE){u,v,h[u],w}; h[u] = ne++;
	ed[ne] = (EDGE){v,u,h[v],w}; h[v] = ne++;
}
int n,m,S1,T1,S2,T2;
int d[4][maxn],vis[maxn];
struct node{int u,d;};
inline bool operator <(const node& a,const node& b){return a.d > b.d;}
priority_queue<node> q;
void dijkstra(int S,int p){
	for (int i = 1; i <= n; i++) d[p][i] = INF,vis[i] = false;
	d[p][S] = 0;
	node u;
	q.push((node){S,d[p][S]});
	while (!q.empty()){
		u = q.top(); q.pop();
		if (vis[u.u]) continue;
		vis[u.u] = true;
		Redge(u.u) if (!vis[to = ed[k].to] && d[p][to] > d[p][u.u] + ed[k].w){
			d[p][to] = d[p][u.u] + ed[k].w;
			q.push((node){to,d[p][to]});
		}
	}
}
int de[maxn],f[maxn];
queue<int> Q;
void solve(){
	dijkstra(S1,0); dijkstra(T1,1);
	dijkstra(S2,2); dijkstra(T2,3);
	for (int k = 2; k < ne; k++)
		if (d[0][ed[k].from] + ed[k].w + d[1][ed[k].to] == d[0][T1])
			ed[k].f = true,de[ed[k].to]++;
	Q.push(S1);
	int u;
	while (!Q.empty()){
		u = Q.front(); Q.pop();
		Redge(u) if (ed[k].f){
			if (d[2][u] + ed[k].w + d[3][to = ed[k].to] == d[2][T2] || d[3][u] + ed[k].w + d[2][to = ed[k].to] == d[2][T2])
				f[to] = max(f[to],f[u] + ed[k].w);
			if (!(--de[to])) Q.push(to);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) ans = max(ans,f[i]);
	printf("%d\n",ans);
}
int main(){
	n = read(); m = read();
	S1 = read(); T1 = read(); S2 = read(); T2 = read();
	int a,b,w;
	for (int i = 1; i <= m; i++){
		a = read(); b = read(); w = read();
		build(a,b,w);
	}
	solve();
	return 0;
}

posted @ 2018-02-26 17:24  Mychael  阅读(181)  评论(0编辑  收藏  举报