Loading

JOI Commuter Pass

JOI Commuter Pass

比较套路但是调试了半天,记录一下。

思路

思路肯定是考虑\(U\to V\)的最短路径是经过一段\(S\to T\)的免费路径还是自己走一波,自己走一波直接最短路即可,对于是否经过了一段最短路径需要DP,不能直接说把\(S\to T\)最短路上的边设为0跑最短路,因为有可能会导致\(U\to V\)走不止一条\(S\to T\)的最短路径的部分,代价会减少?。不太确定在LOJ上只拿了31分。答案貌似都是小了。之后的思路类似于【Elaxia的路线】,但是不可以直接照搬跑正常的拓扑,因为你不知道它是否是按照DAG的顺序来。在最短路上DP,设\(f_i\)表示\(u\)\(i\)的最短路,\(g_i\)表示\(v\)\(i\)的最短路。在每条可能的最短路上进行DP,那么状态转移比较简单就是寻找到到路径上的最小\(f,g\)。但是切记不可以最后直接\(min(ans,f_u+g_u)\)。问题和刚才的直接跑最短路是一样的。如图image

在某个位置可能最短路分叉,而你求的f,g又不在同一条最短路径上,就又会反同样的错误。如果在同一条上这样也一定是可以得到最优答案的。?这里不确定。

image

比如当\(u\)\(f\)所在点或\(g\)所在点时就可以。毕竟是dfs。
其实就是\(f,g\)不一定同时能够取到。

inline void dfs(int u)
{
	if(vis[u]) return ;vis[u] = true;
	f[u] = dis[2][u],g[u] = dis[3][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][T]) continue;
		dfs(j);
		f[u] = min(f[u],f[j]),g[u] = min(g[u],g[j]);
	}
	ans = min({ans,f[u] + dis[3][u],g[u] + dis[2][u]});
}

signed main()
{
	memset(h,-1,sizeof h);
	n = read();m = read();
	S = read();T = read();
	U = read();V = read();
	for(int i = 1;i <= m;i++){
		int a,b,c;
		a = read();b = read();c = read();
		add(a,b,c),add(b,a,c);
	}
	Dijstera(S,0);
	Dijstera(T,1);
	Dijstera(U,2);
	Dijstera(V,3);
	ans = dis[2][V];
	memset(vis,0,sizeof vis);
	dfs(S);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-09-20 16:10  场-room  阅读(36)  评论(0)    收藏  举报