E. Minimum Path(思维+分层图)
发布日期:2021-06-30 10:27:19 浏览次数:2 分类:技术文章

本文共 1585 字,大约阅读时间需要 5 分钟。

观察表达式 ∑ w i − m a x + m i n \sum w_i-max+min wimax+min

首先 ∑ w i \sum w_i wi就是普通的最短路

所以应该往最短路的方向考虑…然后就不知道了…

其实等价于,有一次把边权置零的机会,有一次把边权置两倍的机会,而且需要全部用掉

为什么可以这样等价??

这样跑分层图,用这样的两次机会,一定会分别用在边权最大和最小的边上

因为这是最有利于最小化距离的方式,所以是没问题的

那么有四种状态

0 0 0表示没使用一次机会, 1 1 1表示用了边权为 0 0 0的机会

2 2 2表示用了边权两倍的机会, 3 3 3表示用完了两次机会

值得一提的是 0 0 0可以使用正常的边权转移到 3 3 3

这样可以有效避免当 1 1 1 i i i经过的边等于 1 1 1的情况,因为 m i n min min m a x max max需要两次转移

#include 
using namespace std;#define int long longconst int inf = 1e18;const int maxn = 4e6+10;struct edge{
int to,nxt,w;}d[maxn]; int head[maxn],cnt=1;void add(int u,int v,int w) {
d[++cnt] = (edge){
v,head[u],w},head[u] = cnt; }typedef pair
p;priority_queue

,greater

>q;int vis[maxn],n,m,dis[maxn];void dijstra(int s) {

for(int i=1;i<=4*n;i++) dis[i] = inf, vis[i] = 0; dis[s] = 0; q.push( p(0,s) ); while( !q.empty() ) {
int u = q.top().second; q.pop(); if( vis[u] ) continue; vis[u] = 1; for(int i=head[u];i;i=d[i].nxt ) {
int v = d[i].to; if( dis[v]>dis[u]+d[i].w ) {
dis[v] = dis[u]+d[i].w; if( !vis[v] ) q.push( p(dis[v],v) ); } } }}//0是什么都没有//1是免费,2是双倍,3是全部 signed main(){
cin >> n >> m; for(int i=1;i<=m;i++) {
int l,r,w; scanf("%lld%lld%lld",&l,&r,&w); for(int j=0;j<=3;j++) add(l+j*n,r+j*n,w),add(r+j*n,l+j*n,w); add(l,r+n,0); add(r,l+n,0); add(l,r+2*n,2*w); add(r,l+2*n,2*w); add(l,r+3*n,w); add(r,l+3*n,w); add(l+n,r+3*n,2*w); add(r+n,l+3*n,2*w); add(l+2*n,r+3*n,0 ); add(r+2*n,l+3*n,0 ); } dijstra(1); for(int i=2;i<=n;i++) cout << dis[i+3*n] << " "; return 0;}

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/112758811 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:F. Strange Set(优化最大权闭合子图)
下一篇:1473C. No More Inversions(数学+详细证明过程)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月22日 08时50分38秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章