给定一张图,同时可以最多让k条不同的边的长度缩短一半
求节点1到节点n的最短路
4 4 1
1 2 4
4 2 6
1 3 8
3 4 8
7
#include <bits/stdc++.h>
using namespace std;
struct Map{
int next;
int to;
int w;
}node[10009]; // 链式前向星存图
int first[1009];
int book[1000][100]; // 标记
struct Heap{
int dis;
int sc;
int i;
}heap[40009]; // 建结构体存堆
int dis[1000][100];
// 存图上距离,其实dis[i][j]中的这个j也可以理解为使用了j张sc后1到i的距离
int Heap_size,cnt;
int ans=2147483647;
inline void Add_ (int u,int v,int w){ // 链式前向星存图
node[++cnt].next=first[u];
first[u]=cnt;
node[cnt].to=v;
node[cnt].w=w;
return;
}
inline void Puts_ (int DIS,int SC,int I){ // 用堆优化Dijkstra
heap[++Heap_size].dis=DIS;
heap[Heap_size].sc=SC;
heap[Heap_size].i=I;
int next,now=Heap_size;
while (now>1){
next=now>>1;
if (heap[now].dis>=heap[next].dis) return;
swap (heap[now],heap[next]);
now=next;
}
return;
}
inline Heap Gets_ (){
Heap res=heap[1];
heap[1]=heap[Heap_size--];
int next,now=1;
while ((now<<1)<=Heap_size){
int next=now<<1;
if (next<Heap_size&&heap[next+1].dis<heap[next].dis) next++;
if (heap[now].dis<=heap[next].dis) return res;
swap (heap[now],heap[next]);
now=next;
}
return res;
}
int n,m,k;
int main (){
scanf ("%d %d %d",&n,&m,&k); // 正常的输入 连边
for (register int i=1,u,v,w;i<=m;++i){
scanf ("%d %d %d",&u,&v,&w);
Add_ (u,v,w);
Add_ (v,u,w);
}
memset (dis,0x3f,sizeof (dis)); // dis数组初始化为极大值
dis[1][0]=0; // 第一层的起点的dis初始化为0
Puts_ (0,0,1); // 将起点放入堆中
while (Heap_size){
Heap Cirno=Gets_ (); // 取出堆顶
if (book[Cirno.i][Cirno.sc]) continue; // 如果该点已经用过了就跳过
book[Cirno.i][Cirno.sc]=1; // 标记该点已用
for (register int i=first[Cirno.i];i;i=node[i].next){
int to=node[i].to;
if (dis[to][Cirno.sc]>dis[Cirno.i][Cirno.sc]+node[i].w){ // 这里是在同一层上的Dij,和正常的差不多
dis[to][Cirno.sc]=dis[Cirno.i][Cirno.sc]+node[i].w;
Puts_ (dis[to][Cirno.sc],Cirno.sc,to); // 将更新后的点放入堆中
}
if ((Cirno.sc<k)&&(dis[to][Cirno.sc+1]>dis[Cirno.i][Cirno.sc]+node[i].w/2)){
// Cirno.sc<k 表示下一层非最顶层
// 即还可以继续向上使用sc拓展
// 注意更新的点在上一层
// 并且两点间距离要变为原来的1/2
dis[to][Cirno.sc+1]=dis[Cirno.i][Cirno.sc]+node[i].w/2;
Puts_ (dis[to][Cirno.sc+1],Cirno.sc+1,to); // 放入堆的操作也差不多,注意Cirno.sc要+1表示是上一层的dis
}
}
}
for (int i=0;i<=k;++i) // 最后再扫一遍得出最小值,因为无法保证使用所有的sc一定距离最小
ans=min (ans,dis[n][i]);
printf ("%d\n",ans);
return 0;
}
原文:https://www.cnblogs.com/IQZ-HUCSr-TOE/p/12631020.html