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)\)。问题和刚才的直接跑最短路是一样的。如图
在某个位置可能最短路分叉,而你求的f,g又不在同一条最短路径上,就又会反同样的错误。如果在同一条上这样也一定是可以得到最优答案的。?这里不确定。

比如当\(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;
}
艰难困苦,玉汝于成

浙公网安备 33010602011771号