分层图
引入:P4822
我们可以建出一个 \(k + 1\) 层的图,第 \(i\) 层指的是使用了 \(i - 1\) 次的 SpellCard。
每一层的一个点到每一层的另一个按照正常的方式连就行了。
另一种情况就是层与层的连边,也就是使用 SpellCard。
假如说有一条起点为 \(u\) 终点为 \(v\) 长度为 \(w\) 的边。
于是我们按照题意就知道从第 \(i\) 层的 \(u\) 连到第 \(i + 1\) 层的 \(v\) 可以连一条长度为 \(w \div 2\)。
同理从第 \(i\) 层的 \(v\) 连到第 \(i + 1\) 层的 \(u\) 可以连一条长度为 \(w \div 2\)。但是这两条边都是有向边。
这样这题的边就连完了,直接从第 \(1\) 层的 \(1\) 号点开始跑最短路,答案就是 \(min(dis_{n \times i})\) 其中 \(1 \le i \le k + 1\)。
附上主函数的代码:
int main()
{
cin >> n >> m >> k;
for(int i = 1;i <= m;i++)
{
int u,v,w;
cin >> u >> v >> w;
for(int j = 1;j <= k + 1;j++)
{
add_edge(t(u,j),t(v,j),w);
add_edge(t(v,j),t(u,j),w);
add_edge(t(u,j),t(v,j + 1),w / 2);
add_edge(t(v,j),t(u,j + 1),w / 2);
}
}
dij();
int ans = 1e9;
for(int i = 1;i <= k + 1;i++)
{
ans = min(ans,dis[n * i]);
// cout << dis[n * i] << '\n';
}
cout << ans;
return 0;
}
然后再给大家两道练习题:P4568,P2939