bzoj1880 [SDOI2009]Elaxia的路线
题目描述
最近,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。
输出格式:
一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)
题解
题目已经规定了公共路径在两个对点的最短路上,所以以四个点为起点跑spfa。
遍历一下每条边,如果这条边满足在两对点的最短路上,就把这条边放进新图。容易证明新图是一个没有环的图,所以拓扑排序跑最长链就可以了。
满足一条边在最短路上的条件就是:起点到这个条边的起点的距离+终点到这条边的距离+这条边的长度=起点到终点的最短路
但是其实两个人在公共路径上走的方向不同也可以,所以要反向再做一次
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<queue> #define maxn 1510 using namespace std; struct edge{ int next,to,w; }e[maxn*maxn*2]; int cnt,n,m,head[maxn],Head[maxn]; int x1,y1,x2,y2,ans; int s1[maxn],s2[maxn],t1[maxn],t2[maxn]; int du[maxn]; bool vis[maxn]; void insert(int u,int v,int w){ cnt++; e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w; head[u]=cnt; } void Insert(int u,int v,int w){ cnt++; e[cnt].next=Head[u];e[cnt].to=v;e[cnt].w=w; Head[u]=cnt; } queue<int>q; void spfa(int x,int dis[]){ memset(dis,127,sizeof (int)*1510); dis[x]=0;q.push(x); vis[x]=1; while(!q.empty()){ int now=q.front();q.pop(); vis[now]=0; for(int i=head[now];i;i=e[i].next){ int s=e[i].to; if(dis[s]>dis[now]+e[i].w){ dis[s]=dis[now]+e[i].w; if(!vis[s]){ vis[s]=1; q.push(s); } } } } } inline void topologysort() { int dis[10000]; memset(dis,0,sizeof(dis)); for(int i=1;i<=n;i++) if(!du[i]) q.push(i); while(!q.empty()) { int tmp=q.front();q.pop(); ans=max(ans,dis[tmp]); for(int i=Head[tmp];i;i=e[i].next) { dis[e[i].to]=max(dis[e[i].to],dis[tmp]+e[i].w); if(!--du[e[i].to]) q.push(e[i].to); } } } int main(){ scanf("%d%d",&n,&m); scanf("%d%d%d%d",&x1,&y1,&x2,&y2); int u,v,w; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); insert(u,v,w);insert(v,u,w); } spfa(x1,s1);spfa(y1,t1);spfa(x2,s2);spfa(y2,t2); for(int tmp=1;tmp<=n;tmp++){ for(int i=head[tmp];i;i=e[i].next){ int s=e[i].to; if(s1[tmp]+e[i].w+t1[s]==s1[y1]&&s2[tmp]+e[i].w+t2[s]==s2[y2]){ Insert(tmp,s,e[i].w); du[s]++; } } } topologysort(); memset(Head,0,sizeof Head); for(int tmp=1;tmp<=n;tmp++){ for(int i=head[tmp];i;i=e[i].next){ int s=e[i].to; if(s1[tmp]+e[i].w+t1[s]==s1[y1]&&s2[s]+e[i].w+t2[tmp]==s2[y2]){ Insert(tmp,s,e[i].w); du[s]++; } } } topologysort(); printf("%d",ans); }
不得了啊,那边的洛谷上有一道这个题的重题啊(P2149&P2109),快去水一发啊!