E. Minimum Path(思维+分层图)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Minimum Path(思维+分层图)相关的知识,希望对你有一定的参考价值。
观察表达式 ∑ w i − m a x + m i n \\sum w_i-max+min ∑wi−max+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 <bits/stdc++.h>
using namespace std;
#define int long long
const 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<int,int>p;
priority_queue<p,vector<p>,greater<p> >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;
以上是关于E. Minimum Path(思维+分层图)的主要内容,如果未能解决你的问题,请参考以下文章