Living-Dream 系列笔记 第41期
稍微讲一下 dijkstra qwq。
dijkstra、bellman-ford(or spfa)、bfs 的区别:
- 
dijkstra 以点为研究对象; 
- 
bellman-ford / spfa 则以边为研究对象; 
- 
而 bfs 可以看作边权为 \(1\)(or 全都相同)的 dijkstra,因此它可以用队列实现。 
dijkstra 的具体实现:
- 
将所有点分为两类(黑点 / 白点),分别代表已确定 / 未确定最短路的点。 
- 
每次在白点中选取与起点距离最近的点 \(u\) 染黑,并对所有 \(u \to v\) 进行松弛操作。 
其中,距离取 \(\min\) 的操作若直接找是 \(O(n^2)\) 的,套个堆就能做到 \(O(n \log n)\)。
dijkstra 的理论依据(以下简称 引理):
- 
在一张仅有正边权的图中,对于一白点 \(u\),若它在 dijkstra 中被选中了,则一定不存在另一白点 \(v\),使得 \(dis_{s,v}+dis_{v,u}<dis_{s,u}\)(\(s\) 为起点,\(dis_{u,v}\) 表示 \(u,v\) 之间的最短路)。 
- 
证明: 采用反证法。 假设存在不同于 \(u\) 的一白点 \(v\),使得 \(dis_{s,v}+dis_{v,u}\) 比 \(dis_{s,u}\) 更短, 因为 \(u\) 在 dijkstra 中被选上了,根据 dijkstra 的实现过程,可得 \(dis_{s,u}<dis_{s,v}\), 又因图中仅有正边权,所以有 \(dis_{s,u}<dis_{s,v}+dis_{v,u}\),这与假设不符,命题得证。 证毕。 
dijkstra 的注意事项:
- 
dijkstra 无法用于正负交替边权(全负边权可以转正数后跑)。 
- 
dijkstra 无法跑最长路。 
- 
以上均可用 引理 来解释,在此不再赘述。 
T1
brute-force dijkstra 板子。
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=5e5+5;
int n,m,s;
int dis[N];
bool vis[N];
struct node{ int v,w; };
vector<node> G[M];
void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	for(int i=1;i<=n;i++){
		int mini=1e9,id=0;
		for(int j=1;j<=n;j++)
			if(mini>dis[j]&&!vis[j]) mini=dis[j],id=j;
		vis[id]=1;
		for(node j:G[id])
			if(dis[j.v]>dis[id]+j.w)
				dis[j.v]=dis[id]+j.w;
	}
}
int main(){
	cin>>n>>m>>s;
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		G[u].push_back({v,w});
	}
	dijkstra();
	for(int i=1;i<=n;i++) cout<<(dis[i]==0x3f3f3f3f?2147483647:dis[i])<<' ';
	return 0;
} 
T2
堆优化 dijkstra 板子。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,M=2e5+5;
int n,m,s;
int dis[N];
bool vis[N];
struct Edge{ int v,w; };
struct Node{
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	}
};
vector<Edge> G[M];
inline int read() {
	int x = 0, f = 1; char ch = getchar();
    while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
inline void write(int x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	priority_queue<Node> pq;
	pq.push({s,0});
	while(!pq.empty()){
		Node cur=pq.top(); pq.pop();
		if(vis[cur.u]) continue; vis[cur.u]=1;
		for(Edge j:G[cur.u])
			if(dis[j.v]>dis[cur.u]+j.w)
				dis[j.v]=dis[cur.u]+j.w,
				pq.push({j.v,dis[j.v]});
	}
}
signed main(){
	n=read(),m=read(),s=read();
	for(int i=1,u,v,w;i<=m;i++){
		u=read(),v=read(),w=read();
		G[u].push_back({v,w});
	}
	dijkstra();
	for(int i=1;i<=n;i++) write(dis[i]),putchar(' ');
	return 0;
} 
T3
无向图上的堆优化 dijkstra 板子。
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
int dis[3031];
bool vis[3031];
struct Edge{ int v,w; };
struct Node{ 
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	} 
};
vector<Edge> G[7031];
void dijkstra(){
	memset(dis,0x3f,sizeof(dis)),dis[s]=0;
	priority_queue<Node> pq; pq.push({s,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]+i.w&&i.v!=now.u)
				dis[i.v]=dis[now.u]+i.w,
				pq.push({i.v,dis[i.v]});
		}
	}
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w;i<=m;i++)
		cin>>u>>v>>w,
		G[u].push_back({v,w}),
		G[v].push_back({u,w});
	dijkstra();
	cout<<dis[t];
	return 0;
}
T4
\(2 \times n\) 遍 dijkstra 即可。
似乎有更优做法,但是我先咕着。
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
int dis[3031];
bool vis[3031];
struct Edge{ int v,w; };
struct Node{ 
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	} 
};
vector<Edge> G[7031];
void dijkstra(int s){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis)),dis[s]=0;
	priority_queue<Node> pq; pq.push({s,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]+i.w&&i.v!=now.u)
				dis[i.v]=dis[now.u]+i.w,
				pq.push({i.v,dis[i.v]});
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1,u,v,w;i<=m;i++) 
		cin>>u>>v>>w,G[u].push_back({v,w});
	for(int i=2;i<=n;i++)
		dijkstra(1),ans+=dis[i],
		dijkstra(i),ans+=dis[1];
	cout<<ans;
	return 0;
}
T5
容易发现开关初始状态边权为 \(0\),其余边权均为 \(1\)。
于是如此建图跑 dijkstra 即可。
#include<bits/stdc++.h>
using namespace std;
int n,a,b,ans;
int dis[131];
bool vis[131];
struct Edge{ int v,w; };
struct Node{ 
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	} 
};
vector<Edge> G[10031];
void dijkstra(int s){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis)),dis[s]=0;
	priority_queue<Node> pq; pq.push({s,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]+i.w&&i.v!=now.u)
				dis[i.v]=dis[now.u]+i.w,
				pq.push({i.v,dis[i.v]});
		}
	}
}
int main(){
	cin>>n>>a>>b;
	for(int i=1,k;i<=n;i++){
		cin>>k;
		for(int j=1,v;j<=k;j++)
			cin>>v,G[i].push_back({v,(j==1?0:1)});
	}
	dijkstra(a),cout<<(dis[b]==0x3f3f3f3f?-1:dis[b]);
	return 0;
}
T6
边权设为 \(1-w \times 0.01\),倒序从 \(B\) 推算出 \(A\) 即可。
#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,ans;
double dis[2031];
bool vis[2031];
struct Edge{ int v; double w; };
struct Node{ 
	int u; double w;
	bool operator < (const Node &b) const{
		return w>b.w;
	} 
};
vector<Edge> G[200031];
void dijkstra(int s){
	memset(vis,0,sizeof(vis));
	for(int i=0;i<=n+1;i++) dis[i]=2147483647.0;
	dis[s]=100.0;
	priority_queue<Node> pq; pq.push({s,100.0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]/i.w)
				dis[i.v]=dis[now.u]/i.w,pq.push({i.v,dis[i.v]});
		}
	}
}
int main(){
	//freopen("P1576_1.in","r",stdin);
	cin>>n>>m;
	for(int i=1,u,v,w;i<=m;i++)
		cin>>u>>v>>w,G[u].push_back({v,1.0-w*0.01}),G[v].push_back({u,1.0-w*0.01});	
	cin>>a>>b;
	dijkstra(b),cout<<setprecision(8)<<fixed<<dis[a];
	return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号