题目描述
爬山是wlswls最喜欢的活动之一。
在一个神奇的世界里,一共有nn座山,mm条路。
wlswls初始有kk点体力,在爬山的过程中,他所处的海拔每上升1m1m,体力会减11点,海拔每下降1m1m,体力会加一点。
现在wlswls想从11号山走到nn号山,在这个过程中,他的体力不能低于00,所以他可以事先花费一些费用请dlsdls把某些山降低,将一座山降低ll米需要花费l*ll∗l的代价,且每座山的高度只能降低一次。因为wlswls现在就在11号山上,所以这座山的高度不可降低。
wlswls从11号山到nn号山的总代价为降低山的高度的总代价加上他走过的路的总长度。
wlswls想知道最小的代价是多少。
输入描述
第一行三个整数nn,mm,kk。
接下来一行nn个整数,第ii个整数h_ihi表示第ii座山的高度。
接下来mm行,每行三个整数xx,yy,zz表示xyxy之间有一条长度为zz的双向道路。
经过每条路时海拔是一个逐步上升或下降的过程。
数据保证11号山和nn号山联通。
1 leq n, k, h_i, z leq 1000001≤n,k,hi,z≤100000
1 leq m leq 2000001≤m≤200000
1 leq x, y leq n1≤x,y≤n
x eq yx̸=y
输出描述
一行一个整数表示答案。
样例输入 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
去年的题,其实当时写了,两个板子,有一个过了一个没过,今天又看到这道题了,打算改一改,改了一下午,一直过不去,最后发现初始化有点问题,有一个是比数据范围大一点点的初始化,一个是直接memset初始化,因为以前memset初始化写超时过,所以就没在意,结果发现就是这里错了。。。啊啊啊啊啊啊啊啊啊,哭死。初始化的时候,要比最大值大一点初始化,for循环的初始化,改成1e18就可以。之所以memset是对的,是因为填充的时候,inf比实际的要大。
思路就是把体力值加到路径里面,然后想一想,发现有几分道理,只要往上走才会掉值,emnnnn,反正感觉有点怪,就是把体力值加到路径里面然后跑个最短路就可以了。
两个版本的dijkstra,随便看着玩吧。。。
代码1(短一点):
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #include<cassert> 7 #include<cctype> 8 #include<cmath> 9 #include<cstdlib> 10 #include<ctime> 11 #include<deque> 12 #include<iomanip> 13 #include<list> 14 #include<map> 15 #include<queue> 16 #include<set> 17 #include<stack> 18 #include<vector> 19 using namespace std; 20 typedef long long ll; 21 typedef long double ld; 22 typedef pair<int,int> pii; 23 24 const double PI=acos(-1.0); 25 const double eps=1e-6; 26 const ll mod=1e9+7; 27 const int inf=0x3f3f3f3f; 28 const int maxn=1e5+10; 29 const int maxm=100+10; 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 31 32 int n,m,k; 33 int cnt=0,head[maxn<<2]; 34 bool vist[maxn]; 35 ll dis[maxn],body[maxn]; 36 priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q; 37 38 struct node{ 39 int v,nex; 40 ll w; 41 }edge[maxn<<2]; 42 43 void add(int u,int v,ll w) 44 { 45 edge[cnt].v=v; 46 edge[cnt].w=w; 47 edge[cnt].nex=head[u]; 48 head[u]=cnt++; 49 } 50 51 void dijkstra(int s) 52 { 53 dis[s]=0;//到自己的最短距离直接设为0 54 q.push(make_pair(0,s)); 55 while(!q.empty()){//队列非空 56 int u=q.top().second;q.pop(); 57 vist[u]=true; 58 for(int i=head[u];~i;i=edge[i].nex){ 59 int v=edge[i].v; 60 ll w=edge[i].w+(body[v]>k?(body[v]-k)*(body[v]-k):0); 61 if(dis[v]>dis[u]+w){//满足条件更新距离 62 dis[v]=dis[u]+w; 63 //p[v]=u;//保存路径 64 q.push(make_pair(dis[v],v));//把更新完的值压入队列 65 } 66 } 67 } 68 } 69 70 int main() 71 { 72 memset(head,-1,sizeof(head));//初始化数组 73 memset(vist,false,sizeof(vist)); 74 memset(dis,inf,sizeof(dis)); 75 cin>>n>>m>>k; 76 for(int i=1;i<=n;i++) 77 cin>>body[i]; 78 for(int i=1;i<=m;i++){ 79 int u,v;ll w; 80 cin>>u>>v>>w; 81 add(u,v,w); 82 add(v,u,w);//无向图相互可达 有向图一次就好 83 } 84 k+=body[1]; 85 dijkstra(1); 86 cout<<dis[n]<<endl; 87 }
代码2(队友的板子,哈哈哈哈):
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #include<cassert> 7 #include<cctype> 8 #include<cmath> 9 #include<cstdlib> 10 #include<ctime> 11 #include<deque> 12 #include<iomanip> 13 #include<list> 14 #include<map> 15 #include<queue> 16 #include<set> 17 #include<stack> 18 #include<vector> 19 using namespace std; 20 typedef long long ll; 21 typedef long double ld; 22 typedef pair<int,int> pii; 23 24 const double PI=acos(-1.0); 25 const double eps=1e-6; 26 const ll mod=1e9+7; 27 const int inf=0x3f3f3f3f; 28 const int maxn=1e5+10; 29 const int maxm=100+10; 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 31 32 int n,m,k; 33 int done[maxn],p[maxn];//d[i]表示i点到起点s的最短路距离,p[i]表示起点s到i的最短路径与i点相连的上一条边 34 ll d[maxn],body[maxn];//done[u]==1表示u点到起点s的最短路已经找到 35 36 struct edge{ //边结构体; 37 int from,to; 38 ll dis; 39 }; 40 41 vector<edge> edges; //边集 无向图 边数*2 42 vector<int> g[maxn]; //g数组存的是边的序号 43 44 struct mindis{ //压入优先队列的结构体 因为d[u]和u要绑定起来 才可标记 u是否已确定最短路; 45 ll d; 46 int u; 47 48 bool operator <(const mindis& rhs)const{ 49 return d>rhs.d; //距离最小值优先 距离相等无所谓 随便一个先出 边权是正的 两个会依次访问 不会影想结果 50 } 51 }; 52 53 priority_queue<mindis> q; //优先队列 小顶堆 最小值优先 54 55 void addedge(int from,int to,ll dis) //加边操作 56 { 57 edges.push_back((edge){from,to,dis}); //将边压入边集 58 int k=edges.size(); 59 g[from].push_back(k-1); //k-1为边序号 以后调用边集数组要从下标0开始 所以边的编号从0开始 将边序号压入已from为起点的数组 60 } 61 62 void dijkstra(int s) //主算法 63 { 64 d[s]=0; //到自己的最短距离直接设为0 65 q.push((mindis){0,s}); 66 while(!q.empty()){ //队列非空 67 mindis x=q.top(); //取当前最小值 68 q.pop(); 69 int u=x.u; 70 if(done[u]==1) continue; //已确定路径直接跳过 71 done[u]=1; //标记 已确定 72 for(int i=0;i<g[u].size();i++){ 73 edge e=edges[g[u][i]]; //g[u][i]表示以u为起点的第i条边在边集edges中的下标 74 ll w=e.dis+(body[e.to]>k?(body[e.to]-k)*(body[e.to]-k):0); 75 if(d[e.to]>d[u]+w){ //满足条件更新距离 76 d[e.to]=d[u]+w; 77 p[e.to]=g[u][i]; //保存路径 78 q.push((mindis){d[e.to],e.to}); //把更新完的值压入队列 79 } 80 } 81 } 82 } 83 84 int main() 85 { 86 memset(done,0,sizeof(done)); //初始化数组 87 memset(p,-1,sizeof(p)); 88 //memset(d,inf,sizeof(d)); 89 cin>>n>>m>>k; 90 for(int i=0;i<=n;i++) //把距离初始化为 inf 不能用memset 自己估算一下路径最长有多长 inf定义大一点就好 91 d[i]=1e18; 92 for(int i=1;i<=n;i++) 93 cin>>body[i]; 94 for(int i=1;i<=m;i++){ 95 int u,v;ll w; 96 cin>>u>>v>>w; 97 addedge(u,v,w); 98 addedge(v,u,w); //无向图相互可达 有向图一次就好 99 } 100 k+=body[1]; 101 dijkstra(1); 102 cout<<d[n]<<endl; 103 }
好想找队友聊天,但是放假了,不能打扰,超乖.jpg。
溜了,我姐的狗窝没有吃的,要饿死了(;´д`)ゞ