CCPC-Wannafly Winter Camp Day1 Div1 - 爬爬爬山 - [最短路][堆优化dijkstra]

题目链接:https://zhixincode.com/contest/3/problem/F?problem_id=39

 

样例输入 1 

4 5 1
1 2 3 4
1 2 1
1 3 1
1 4 100
2 4 1
3 4 1

样例输出 1

6

题解: 

这个体力感觉跟势能是个差不多的东西……很显然,如果没有降低山峰的能力,wls最多只能爬高度为 $h[1]+k$ 的山,更高的就爬不了。

因此,这个就是同时有点权和边权的最短路,只要在松弛有向边的时候判断一下该边的终点是否需要另外花费即可。

或者,换种更简单的思路来说,对于每条有向边,若其终点 $v$ 的山的高度超过 $h[1]+k$,那么该边边权额外增加 $(h[v] - h[1] - k)^2$。 

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> P; //first是最短距离,second是节点编号
#define mk(x,y) make_pair(x,y)

const int maxn=1e5+10;
const ll INF=1e17;

int n,m,k;
ll h[maxn];

struct Edge{
    int u,v;
    ll w;
};
vector<Edge> E;
vector<int> G[maxn];
void addedge(int u,int v,ll w)
{
    E.push_back((Edge){u,v,w});
    G[u].push_back(E.size()-1);
}

ll dist[maxn];
bool vis[maxn];
priority_queue< P, vector<P>, greater<P> > Q;
void dijkstra(int s,int t)
{
    for(int i=1;i<=n;i++) dist[i]=INF, vis[i]=0;
    dist[s]=0, Q.push(mk(0,s));
    while(!Q.empty())
    {
        int u=Q.top().second; Q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(auto x:G[u])
        {
            Edge &e=E[x]; int v=e.v;
            if(vis[v]) continue;
            if(dist[v]>dist[u]+e.w) dist[v]=dist[u]+e.w, Q.push(mk(dist[v],v));
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%lld",&h[i]);
    for(int i=1;i<=m;i++)
    {
        int u,v; ll w,o;
        scanf("%d%d%lld",&u,&v,&w);
        o=0; if(h[1]+k<h[v]) o=(h[v]-h[1]-k)*(h[v]-h[1]-k);
        addedge(u,v,w+o);
        o=0; if(h[1]+k<h[u]) o=(h[u]-h[1]-k)*(h[u]-h[1]-k);
        addedge(v,u,w+o);
    }
    dijkstra(1,n);
    cout<<dist[n]<<endl;
}

猜你喜欢

转载自www.cnblogs.com/dilthey/p/10428457.html