题目链接:https://www.zhixincode.com/contest/7/problem/F?problem_id=97
人话题意:n座山,每座山都有一个高度,海拔上升一米体力增加1点,下降一米减少1点。山与山之间有一个距离x,你可以降低山的高度l,代价为l*l,刚开始在1号山,要去n号山(最终体力值要大于等于零),求最小代价。
思路:刚开始在1号山,一定要下山,所以初始体力值应该为k + h[1],对于一座山,如果要砍,就一定要砍到(k + h[1])的高度为止,将这部分额外的花费加到边的权值上。注意双向边要分开来建。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e6+7;
#define inf 0x3f3f3f3f
#define pii pair<ll, ll>
int n, m, s, t, k;
ll d[maxn], h[maxn]; int vis[maxn];
vector<pair<int, ll>>E[maxn];
void init()
{
for(int i = 0; i <= n; i++) E[i].clear();
memset(d,0x3f,sizeof(d));
memset(vis,0,sizeof(vis));
}
void Dijkstra()
{
d[s] = 0;
priority_queue<pii> Q;
//priority_queue<pii,vector<pii>,greater<pii> > Q;
Q.push({-d[s],s});
while(!Q.empty())
{
int now = Q.top().second;
Q.pop(); if(vis[now]) continue;
vis[now] = 1;
for(int j = 0; j < E[now].size(); j++)
{
int v = E[now][j].first;
if(!vis[v] && d[v] > d[now]+E[now][j].second)
{
d[v] = d[now]+E[now][j].second;
Q.push({-d[v],v});
}
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
init(); scanf("%lld",&h[1]);
k += h[1];
for(int i = 2; i <= n; i++)
scanf("%lld",&h[i]);
int a, b; ll x;
while(m--)
{
scanf("%d%d%lld",&a,&b,&x);
if(h[b] >= k) E[a].push_back({b,x+(h[b]-k)*(h[b]-k)});
else E[a].push_back({b,x});
if(h[a] >= k) E[b].push_back({a,x+(h[a]-k)*(h[a]-k)});
else E[b].push_back({a,x});
}
s = 1, t = n;
Dijkstra();
printf("%lld\n",d[t]);
}
return 0;
}