利用Dijikstra最短路特定写法求次短路,DP

第一题:2019暑假牛客第4场J-free:
在这里插入图片描述
在这里插入图片描述
官方题解:
在这里插入图片描述
AC代码:

#include<bits/stdc++.h>
#define per(i,a,b) for(int i = (a);i <= (b);++i)
#define rep(i,a,b) for(int i = (a);i >= (b);--i)
using namespace std;
#define INF 1e9
const int maxn = 1e5 + 10;
int n = 0,m = 0,s = 0,t = 0,k = 0;
int head[maxn],cnt = 0;
int dist[maxn];
struct node{
	int v,dis,kk;
	bool operator < (const node& c)const{
		return c.dis > this->dis;
	}
};
struct Edge{
	int to,w,nex;
}e[maxn];
void init(){
	cnt = 0;
	per(i,1,n){
		head[i] = -1; dist[i] = INF;
	}
}
void add_edge(int from,int to,int w){
	e[++cnt].to = to;
	e[cnt].w = w;
	e[cnt].nex = head[from];
	head[from] = cnt;
}
int dijikstra(){//将DP嵌入最短路中,或者说最短路就是DP,还有要使用这种写法,才能将DP嵌入
	dist[s] = 0;//最短路还有次短路都要储存
	priority_queue<node> pq;
	pq.push(node{s,0,0});
	while(!pq.empty()){
		node u = pq.top(); pq.pop();
		for(int i = head[u.v];i != -1;i = e[i].nex){
			int to = e[i].to;
			if(dist[u.v] + e[i].w < dist[to]){//这条边不选为免费边
				dist[to] = dist[u.v] + e[i].w;
				pq.push(node{to,dist[to],u.kk});
			}
			if(u.kk < k){//可行性判断
				if(dist[to] > u.dis){//优化判断
					dist[to] = u.dis;//将这条边变为免费边
					pq.push(node{to,dist[to],u.kk+1});
				}
			}
		}
	}
	return dist[t];
}
int main(){
	while(~scanf("%d %d %d %d %d",&n,&m,&s,&t,&k)){
		init();
		per(i,1,m){
			int a = 0,b = 0,l = 0;
			scanf("%d %d %d",&a,&b,&l);
			add_edge(a,b,l); add_edge(b,a,l);
		}
		int ans = dijikstra();
		printf("%d\n",ans);
	}

	return 0;
}

第二题:杭电多校HDU6181:
题目传送门
AC code:

#include<bits/stdc++.h>
// #include<iostream>
// #include<cstdio>
// #include<vector>
// #include<cstring>
using namespace std;
#define per(i,a,b) for(int i = (a);i <= (b);++i)
#define rep(i,a,b) for(int i = (a);i >= (b);--i)
const int maxn = 2e5 + 10;
typedef long long LL;
#define INF 1e18
int n = 0,m = 0;
int cnt = 0,head[maxn];
LL d1[maxn],d2[maxn];
bool vis[maxn];
struct Edge{
	int to;
	LL w;
	int nex;
	bool operator < (const Edge& ed)const{
		return ed.w < this->w;//注意符号的顺序
	}
	Edge(){}
	Edge(int to1,LL w1,int nex1){
		to = to1; nex = nex1; w = w1;
	}
};
Edge e[maxn];
void init(){
	cnt = 0;
	per(i,0,n){
		head[i] = -1;
		d1[i] = d2[i] = INF;
	}
}

void add_edge(int from,int to,LL w){
	e[++cnt].to = to;
	e[cnt].w = w;
	e[cnt].nex = head[from];
	head[from]  = cnt;
}

void dijikstra(int s){
	// memset(vis,false,sizeof(vis));
	d1[s] = 0;
	priority_queue<Edge> pq;
	Edge tmp;	
	tmp.to = s; tmp.w= 0;
	pq.push(tmp);
	// Edge Next;
	while(!pq.empty()){
		Edge u = pq.top();
		pq.pop();
		if(d2[u.to] < u.w){	
			continue;
		}
		for(int i = head[u.to];i != -1;i = e[i].nex){
			Edge ed = e[i];
			LL way = u.w + ed.w;//	
			if(d1[ed.to] > way){//最短路
				swap(d1[ed.to],way);
				pq.push(Edge{ed.to,d1[ed.to],ed.nex});
			}
			if(d2[ed.to] > way && d1[ed.to] < way){//记录次短路
				d2[ed.to] = way;
				pq.push(Edge{ed.to,d2[ed.to],ed.nex});
			}
		}
	}

	printf("%lld\n",d2[n]);
}
int main(){
	int T = 0;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&n,&m);
		init();
		per(i,1,m){
			int x = 0,y = 0;
			LL w = 0;
			scanf("%d %d %lld",&x,&y,&w);
			add_edge(x,y,w); add_edge(y,x,w);
		}
		dijikstra(1);
	}

	return 0;
}

也是A*模板题:

#include<bits/stdc++.h>
#define per(i,a,b) for(int i = (a);i <= (b);++i)
#define rep(i,a,b) for(int i = (a);i >= (b);--i)
#define INF 1e18
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
int n = 0,m = 0;
LL d[maxn];
int head[maxn];
int cnt = 0;
bool vis[maxn];
struct node{
	int v;
	LL c;
	bool operator < (const node& x)const{
		return x.c + d[x.v] < this->c + d[this->v];
	}

};
struct Edge{
	int to,nex;
	LL w;
}e[2*maxn];//需要两倍的空间,每一次是有向边
void init(){
	cnt = 0;
	per(i,1,n){
		head[i] = -1;
		d[i] = INF;
		vis[i] = false;
	}
}
void add_edge(int from,int to,LL w){//链式前向星
	e[++cnt].to = to;
	e[cnt].w = w;
	e[cnt].nex = head[from];
	head[from] = cnt;
}

void dijikstra(int s){//求出每个点到终点的距离用于计算期望函数的大小
	//不需要记录非最短的路径长度,所以pq会根据是否访问来排序,未访问的为INF
	//且没有入栈,所以可实现优先选择最优的点
	priority_queue<node> pq;
	d[s] = 0;
	pq.push(node{s,0});
	while(!pq.empty()){
		node u = pq.top();
		pq.pop();
		if(vis[u.v]){
			continue;	
		}
		vis[u.v] = true;
		for(int i = head[u.v];i != -1;i = e[i].nex){
			Edge ed = e[i];
			if(d[ed.to] > d[u.v] + ed.w){
				d[ed.to] = d[u.v] + ed.w;
				pq.push(node{ed.to,0});
			}
		}
	}
}

LL A_start(int s,int k){
	--k;
	priority_queue<node> pq;
	pq.push(node{s,0});
	while(!pq.empty()){
		node u = pq.top();
		pq.pop();
		if(u.v == n){
			if(k > 0){
				--k;
			}else{
				return u.c;
			}
		}
		for(int i = head[u.v];i != -1;i = e[i].nex){
			Edge ed = e[i];
			pq.push(node{ed.to,ed.w + u.c});
			//记录从原点到该点的距离,比较时使用的是期望函数大小,还要+d[ed.to]
		}
	}
	return -1;
}
int main(){
	int T = 0;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&n,&m);
		init();
		per(i,1,m){
			int x = 0,y = 0;
			LL w = 0;
			scanf("%d %d %lld",&x,&y,&w);
			add_edge(x,y,w); add_edge(y,x,w);
		}
		dijikstra(n);
		// per(i,1,n){
		// 	printf("%lld ",d[i]);
		// }
		// puts("");
		printf("%lld\n",A_start(1,2));
	}	

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值