【题解】LuoGu2149:[SDOI2009]Elaxia的路线

原题传送门
先以 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的最短路中的边,是这条边是答案中的一条边的必要条件
如何刻画?

  • d i s x 1 − > i + l e n i , j + d i s y 1 − > j = d i s x 1 − > y 1 dis_{x1->i}+len_{i,j}+dis_{y1->j}=dis_{x1->y1} disx1>i+leni,j+disy1>j=disx1>y1
  • d i s x 2 − > i + l e n i , j + d i s y 2 − > j = d i s x 2 − > y 2 dis_{x2->i}+len_{i,j}+dis_{y2->j}=dis_{x2->y2} disx2>i+leni,j+disy2>j=disx2>y2

把这样的边建一个有向图,做一下拓扑dp就好了

但是还有一个问题,这道题目默认相遇也算是重合
那么还有这种情况的边 ( i , j ) (i,j) (i,j)满足条件

  • d i s x 1 − > i + l e n i , j + d i s y 1 − > j = d i s x 1 − > y 1 dis_{x1->i}+len_{i,j}+dis_{y1->j}=dis_{x1->y1} disx1>i+leni,j+disy1>j=disx1>y1
  • d i s y 2 − > i + l e n i , j + d i s x 2 − > j = d i s x 2 − > y 2 dis_{y2->i}+len_{i,j}+dis_{x2->j}=dis_{x2->y2} disy2>i+leni,j+disx2>j=disx2>y2

这样的边再做一次拓扑就好了
当然上述两种情况不可能同时发生

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;
}

你可能感兴趣的:(题解,LuoGu,最短路,题解,LuoGu,最短路)