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 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 <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(思维+分层图)的主要内容,如果未能解决你的问题,请参考以下文章

Educational Codeforces Round 102 E. Minimum Path(分层图最短路)

E. Common Number (思维 + 规律)

[黑科技]分层图

LeetCode Minimum Path Sum

E. Omkar and Forest 思维,结论

E. Number of Simple Paths(环基树 + 思维)