zoukankan      html  css  js  c++  java
  • 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];
    }
    
  • 相关阅读:
    sql -- 获取商品分类的最新销售情况
    sql -- 获取连续签到的用户列表
    sql -- 利用order by 排名作弊
    sql -- update表子查询、多条件判断case when
    sql-- 找到重复数据并删除、有重复数据不插入或更新的处理方法
    sql--自链接(推荐人)
    sql--测试商品的重要度,是否需要及时补货
    sql面试题
    TCP/IP 3次握手
    REST和SOAP
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14648481.html
Copyright © 2011-2022 走看看