Loading

P2149 [SDOI2009]Elaxia的路线 题解

Elaxia的路线

求两对点间的最短路的最长公共路径。

思路

记录哪些边在公共的最短路径上。做法:跑四遍最短路,判断是否同时满足两个点对disfromS[u]+w[i]+disfromT[v]==disfromS[T]。抠出公共路径(有向的,最短路求后),在公共路径组成的新图上考虑最长路径。转化为套路性问题求最大链长,拓扑排序DP即可。
dijstera更快。

代码

int n,m,id;
int s1,t1,s2,t2;
int h[N],e[M],ne[M],w[M],idx;
int h1[N],e1[M],ne1[M],w1[M],idx1;
int dis[4][N];
int din[N],f[N];
bool vis[N];
inline void add(int a,int b,int c)
{...}

inline void add1(int a,int b,int c)
{...}

inline void spfa(int rt)
{...}

inline void new_graph()
{
	for(int u = 1;u <= n;u++)
	   for(int i = h[u];~i;i = ne[i]){
	   	int j = e[i];
	   	if((dis[0][u] + w[i] + dis[1][j] == dis[0][t1])){//注意判断第二个正反两向边,第一个必然正反都被遍历
	   		if(dis[2][u] + w[i] + dis[3][j] == dis[2][t2]) add1(u,j,w[i]);
	   		if(dis[2][j] + w[i] + dis[3][u] == dis[2][t2]) add1(j,u,w[i]);
		   } 
	   }
}

inline void topsort()
{
	queue<int> q;
	memset(f,-INF,sizeof f);
	for(int i = 1;i <= n;i++){
	   if(!din[i]){
	   	f[i] = 0;
	   	q.push(i);
	   }
	}
	while(q.size())
	{
		int u = q.front();
		q.pop();
		for(int i = h1[u];~i;i = ne1[i]){
			int j = e1[i];din[j]--;
			if(f[j] < f[u] + w1[i]) f[j] = f[u] + w1[i];
			if(!din[j]) q.push(j);
		}
	}
}

signed main()
{
	id = 1;spfa(s1);
	id = 2;spfa(t1);
	id = 3;spfa(s2);
	id = 4;spfa(t2);
	new_graph();
	topsort();
	int mx = -1;
	for(int i = 1;i <= n;i++) mx = max(mx,f[i]);
	printf("%d\n",mx);
	return 0;
}
posted @ 2021-08-11 11:10  场-room  阅读(39)  评论(0)    收藏  举报