原题传送门
先以 x 1 , x 2 , y 1 , y 2 x1,x2,y1,y2 x1,x2,y1,y2为起点跑四遍最短路
答案一定是一条链
对于一条边,同时是 x 1 − > y 1 , x 2 − > y 2 x1->y1,x2->y2 x1−>y1,x2−>y2的最短路中的边,是这条边是答案中的一条边的必要条件
如何刻画?
把这样的边建一个有向图,做一下拓扑dp就好了
但是还有一个问题,这道题目默认相遇也算是重合
那么还有这种情况的边 ( i , j ) (i,j) (i,j)满足条件
这样的边再做一次拓扑就好了
当然上述两种情况不可能同时发生
Code:
#include
#define maxm 3000010
#define maxn 2000
using namespace std;
struct Edge{
int to, next, len;
}edge[maxm], edge2[maxm];
struct heap{
int num, len;
bool operator < (const heap &x) const{ return x.len < len; }
};
priority_queue <heap> q;
queue <int> Q;
int num, num2, head[maxn], head2[maxn], dis[5][maxn], vis[maxn], len[maxn], n, m, deg[maxn], x1, x2, Y1, y2;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void addedge(int x, int y, int z){ edge[++num] = (Edge){y, head[x], z}, head[x] = num; }
void addedge2(int x, int y, int z){ edge2[++num2] = (Edge){y, head2[x], z}, head2[x] = num2, ++deg[y]; }
void dijk(int s, int opt){
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i) dis[opt][i] = 1e9;
dis[opt][s] = 0;
q.push((heap){s, 0});
while (!q.empty()){
heap tmp = q.top(); q.pop();
int u = tmp.num;
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = edge[i].next){
int v = edge[i].to;
if (dis[opt][v] > dis[opt][u] + edge[i].len){
dis[opt][v] = dis[opt][u] + edge[i].len;
if (!vis[v]) q.push((heap){v, dis[opt][v]});
}
}
}
}
void work(){
for (int i = 1; i <= n; ++i) if (!deg[i]) Q.push(i);
while (!Q.empty()){
int u = Q.front(); Q.pop();
for (int i = head2[u]; i; i = edge2[i].next){
int v = edge2[i].to;
len[v] = max(len[v], len[u] + edge2[i].len);
--deg[v];
if (deg[v] == 0) Q.push(v);
}
}
}
int main(){
n = read(), m = read();
x1 = read(), Y1 = read(), x2 = read(), y2 = read();
for (int i = 1; i <= m; ++i){
int x = read(), y = read(), z = read();
addedge(x, y, z), addedge(y, x, z);
}
dijk(x1, 1), dijk(Y1, 2), dijk(x2, 3), dijk(y2, 4);
for (int i = 1; i <= n; ++i)
for (int j = head[i]; j; j = edge[j].next){
int k = edge[j].to, l = edge[j].len;
if (dis[1][i] + l + dis[2][k] == dis[1][Y1] && dis[3][i] + l + dis[4][k] == dis[3][y2])
addedge2(i, k, l);
}
work();
int ans = 0;
for (int i = 1; i <= n; ++i) ans = max(ans, len[i]);
num2 = 0;
memset(head2, 0, sizeof(head2));
memset(len, 0, sizeof(len));
for (int i = 1; i <= n; ++i)
for (int j = head[i]; j; j = edge[j].next){
int k = edge[j].to, l = edge[j].len;
if (dis[1][i] + l + dis[2][k] == dis[1][Y1] && dis[4][i] + l + dis[3][k] == dis[3][y2])
addedge2(i, k, l);
}
work();
for (int i = 1; i <= n; ++i) ans = max(ans, len[i]);
printf("%d\n", ans);
return 0;
}