LGR-084 C Reboot from Blue 贪心 DAG上DP最短路

LGR-084 C Reboot from Blue 贪心 DAG上DP最短路

题意

数轴上有(n)个加油站,第(i)个位于(x_i),油价为每升(c_i)

起点坐标(s),终点(t),车油箱一开始是空的,且保证起点处有加油站,假设箱子容量无限大,一升油可以走距离1

求出最小花费

[1 leq n leq 10^5\ -10^9 leq x_i,s,t leq 10^9,s < t ]

分析

容易想到此题是 51nod1288 的改编

我们肯定贪心地每次走到下一个价格比当前位置小的位置加油,这一性质就可以用单调栈维护,有考虑到这题由往回走的可能性,所以需要一定转化。

对于当前点和左右第一个小于当前点的点连边,边权为距离乘油价,容易知道这样可以构成一张DAG,因此最后只需要在DAG上跑最短路即可,这可以用拓扑排序DP实现。

注意点:1.起点应该保证入度为0,否则无法拓扑排序 2.单调栈实现时,必须找严格小于的位置,否则会形成环。 3.拓扑排序时,一开始必须把所有入度为0的点加入队列,否则可能导致一些点入度始终不能到0的情况

代码

#include<bits/stdc++.h>
#define pii pair<int,ll>
#define fi first
#define se second
#define re register
using namespace std;
typedef long long ll;

const ll MOD = 1e9 + 7;
const int maxn = 1e5 + 5;

ll rd(){
	ll x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

struct Edge{
	int v;
	ll w;
	Edge(int _v,ll _w) :v(_v),w(_w) {}
};

pii p[maxn];
ll dp[maxn];
vector<Edge> e[maxn];
int in[maxn];

 
int main(){
	int n = rd();
	int s = rd();
	int t = rd();
	for(int i = 1;i <= n;i++){
		p[i].se = rd();
		p[i].fi = rd();
	}
	p[++n] = make_pair(t,0);
	sort(p + 1,p + n + 1);
	int ss,tt;
	ss = tt = 1;
	for(int i = 1;i <= n;i++)
		if(p[i].fi == s) ss = i;
		else if(p[i].fi == t && !p[i].se) tt = i;
	
	stack<int> st;
	for(int i = 1;i <= n;i++){
		while(!st.empty() && p[i].se <= p[st.top()].se) {
			st.pop();
		}
		if(!st.empty()) e[i].push_back(Edge(st.top(),p[i].se * (p[i].fi - p[st.top()].fi))),in[st.top()]++;
		if(i ^ ss)
			st.push(i); 
	}
	
	while(!st.empty()) st.pop();
	for(int i = n;i >= 1;i--){
		while(!st.empty() && p[i].se <= p[st.top()].se) {
			st.pop();
		}
		if(!st.empty()) e[i].push_back(Edge(st.top(),-1 * p[i].se * (p[i].fi - p[st.top()].fi))),in[st.top()]++;
		if(i ^ ss)
			st.push(i); 
	}
	
	queue<int> q;
	for(int i = 1;i <= n;i++)
		if(!in[i]) q.push(i);
	for(int i = 1;i <= n;i++)
		dp[i] = 5e18;
	dp[ss] = 0;
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		for(auto v:e[u]) {
			if(dp[v.v] > dp[u] + v.w)
				dp[v.v] = dp[u] + v.w;
			if(!--in[v.v])
				q.push(v.v);
		}
	} 
	cout << dp[tt];
}
原文地址:https://www.cnblogs.com/hznumqf/p/14648481.html