传送门啦
分析:
我最开始想的是跑两遍最短路,然后记录一下最短路走了哪些边(如果有两条最短路就选经过边多的),打上标记。两边之后找两次都标记的边有多少就行了。
但。。。我并没有实现出来。
最后让我们看一下正解:
四边spfa+拓扑排序求最长边
先让我们考虑如何求两对点最短路的最长公共路径?
1.先明白:如果有一条边,它的起点到最短路的起点 + 终点到最短路的终点 + 边权 == 最短路起点到终点的距离,那么这条边一定在最短路上。
也就是说如果有一条边i:from -> to权值是w在最短路x -> y上,那么有disx->from + disto->y + edge[i].w == disx->y
2.所以就可以把两条最短路径都经过的边重新建图
3.最后就是求最长路即可(显然图是DAG 拓扑排序可以求)。
注意!!注意!!注意!!
1.最开始我们建的是无向图,也就是说:dis_{from->to} + wdisfrom−>to+w 和 dis_{to->from} + wdisto−>from+w是一样的。
2.重新建图的时候我们建的是有向图。
最短路和普通的spfaspfa没什么区别,稍微改了一下dis数组,那样就不用开4个dis了。
拓扑序也差不多,ind[i]ind[i]表示第ii点的入度。
总体来说,这个题主要还是想法,还有对基础算法的应用。挺好一个题。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 1505; inline int read(){ char ch = getchar(); int f = 1 , x = 0; while(ch > '9' || ch < '0'){if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();} return x * f; } int n,m,x,y,xx,yy,u,v,w; struct Edge{ int from,to,next,val; int tag; }edge[maxn * maxn] , e[maxn * maxn]; int head1[maxn],tot1,head2[maxn],tot2; int dis[5][maxn],ind[maxn]; bool vis[maxn]; int f[maxn]; void add(int u,int v,int w){ edge[++tot1].to = v; edge[tot1].from = u; edge[tot1].next = head1[u]; edge[tot1].val = w; head1[u] = tot1; } void addedge(int u,int v,int w){ e[++tot2].from = u; e[tot2].to = v; e[tot2].val = w; e[tot2].next = head2[u]; head2[u] = tot2; } void spfa(int s,int flag){ queue<int> q; for(int i=1;i<=n;i++) dis[flag][i] = 1e9; memset(vis,false,sizeof(vis)); q.push(s); dis[flag][s] = 0; vis[s] = true; while(!q.empty()){ int cur = q.front(); q.pop(); vis[cur] = false; for(int i=head1[cur];i;i=edge[i].next){ int v = edge[i].to; if(dis[flag][v] > dis[flag][cur] + edge[i].val){ dis[flag][v] = dis[flag][cur] + edge[i].val; if(vis[v] == 0){ q.push(v); vis[v] = true; } } } } } inline void topo(){ queue<int> que; que.push(x); while(!que.empty()){ int cur = que.front(); que.pop(); for(int i=head2[cur];i;i=e[i].next){ int v = e[i].to , w = e[i].val; --ind[v]; if(!ind[v]) { que.push(v); f[v] = max(f[v] , f[cur] + e[i].tag * w); } } } } void rebuild(){ for(int i=1;i<=tot1;i++){ int v = edge[i].to , u = edge[i].from , w = edge[i].val; if(dis[1][u] + w + dis[2][v] == dis[1][y]){ addedge(u , v , w); if(dis[3][u] + w + dis[4][v] == dis[3][yy] || dis[3][v] + w + dis[4][u] == dis[3][yy]) //为了处理无向图的问题 e[tot2].tag = 1; ind[v]++; } } } int main(){ n = read(); m = read(); x = read(); y = read(); xx = read(); yy = read(); for(int i=1;i<=m;i++){ u = read(); v = read(); w = read(); add(u , v , w); add(v , u , w); } spfa(x , 1); spfa(y , 2); spfa(xx , 3); spfa(yy , 4); rebuild(); topo(); printf("%d ",f[y]); return 0; }