最短路部分题目

一、floyed  时间复杂度O(n^2), 空间复杂度O(n^2)

P1359 租用游艇

#include <bits/stdc++.h>
using namespace std;
#define INF 10000000
int n, g[201][201], dis[201], vis[201];

int main()
{
    cin >> n;
    //初始化 
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
        {
            if(i==j)	g[i][j]=0;
            else    g[i][j]=INF;
        }
    }
    //输入 
    for (int i=1; i<=n-1; i++){
        for(int j=i+1; j<=n; j++)
            cin >> g[i][j];
	}
    }
    //floyed
    for(int k=1; k<=n; ++k){
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
	    	    g[i][j]=min(g[i][j], g[i][k]+g[k][j]);
		}	
	}
    }
    printf("%d", g[1][n]);
    return 0;
}

B3611 【模板】传递闭包

#include <bits/stdc++.h>
using namespace std;
int n, a[110][110];
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			scanf("%d", &a[i][j]);
		}
	}
	for(int k=1; k<=n; ++k){
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				a[i][j]=max(a[i][j], a[i][k]*a[k][j]);
			}
		}
	}
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}
	return 0;
}

P2910 [USACO08OPEN]Clear And Present Danger S

#include <bits/stdc++.h>
using namespace std;
int n, m, a[110][110], asd[10010], ans;
int main()
{
	scanf("%d %d", &n, &m);
	memset(a, 0x3f, sizeof(a));
	for(int i=1; i<=m; ++i){
		scanf("%d", &asd[i]);
	}
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			scanf("%d", &a[i][j]);
		}
	}
	for(int k=1; k<=n; ++k){
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				a[i][j]=min(a[i][j], a[i][k]+a[k][j]);
			}
		}
	}
	asd[0]=1;
	asd[m+1]=n;
	for(int i=0; i<=m; ++i){
		ans+=a[asd[i]][asd[i+1]];
	}
	printf("%d", ans);
	return 0;
}

P6464 [传智杯 #2 决赛] 传送门

#include <bits/stdc++.h>
using namespace std;
int n, m, ans, u, v, w, a[110][110], dis[110][110], cur;
int main()
{
	scanf("%d %d", &n, &m);
	memset(a, 0x3f, sizeof(a));
	for(register int i=1; i<=m; ++i){
		scanf("%d %d %d", &u, &v, &w);
		a[u][v]=w;
		a[v][u]=w;
	}
	for(register int k=1; k<=n; ++k){
		for(register int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				a[i][j]=min(a[i][j], a[i][k]+a[k][j]);
			}
		}	
	}
	for(register int i=1; i<n; ++i){
		for(register int j=i+1; j<=n; ++j){
			ans+=a[i][j];
		}
	}
	for(register int i=1; i<=n; ++i){	
		for(register int j=1; j<=n; ++j){
			//数据回滚 
			for(register int x=1; x<=n; ++x){
				for(register int y=1; y<=n; ++y){
					dis[x][y]=a[x][y];
				}
			}
			dis[i][j]=dis[j][i]=0;	//修路 
			for(register int x=1; x<=n; ++x){
				for(register int y=1; y<=n; ++y){
					dis[x][y]=min(dis[x][y], dis[x][i]+dis[i][y]);
				}
			}
			for(register int x=1; x<=n; ++x){
				for(register int y=1; y<=n; ++y){
					dis[x][y]=min(dis[x][y], dis[x][j]+dis[j][y]);
				}
			}
			cur=0;
			for(register int x=1; x<n; ++x){
				for(register int y=x+1; y<=n; ++y){
					cur+=dis[x][y];
				}
			}
			ans=min(ans, cur);
		}
	}
	printf("%d", ans);
	return 0;
}

二、dijkstra朴素版  时间复杂度O(n^2), 空间复杂度O(n^2)

P1359 租用游艇

#include <bits/stdc++.h>
using namespace std;
#define INF 10000000
int n, g[201][201], dis[201], vis[201];
int main()
{
    cin >> n;
    //初始化 
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
        {
            if(i==j)	g[i][j]=0;
            else	g[i][j]=INF;
        }
    }
    //输入 
    for (int i=1; i<=n-1; i++){
        for(int j=i+1; j<=n; j++)
            cin >> g[i][j];
	}
    }
    //狄杰斯特拉
    for(int i = 1;i <= n;i++)	dis[i]=g[1][i];
    dis[1]=0;
    vis[1]=1;
    for(int i=1; i<=n-1; i++){    //次数
        int flag=INF, u;
        //打擂台,在没找到最短路的点中,找距离源点最近的点
        for(int j=1; j<=n; j++){
            if(!vis[j] && dis[j]<flag){
                flag=dis[j];
                u=j;
            } 
        }
        //找到的这个u点, dis[u]已经是源点到u点的最短路
        vis[u]=1;    //标记找到最短路了
        //基于u点松弛与他相邻的点
        for(int j=1; j<=n; j++)
        {
            dis[j]=min(dis[j], dis[u]+g[u][j]);
        }
    }
    cout << dis[n];
    return 0;
}

三、dijkstra堆优化版  时间复杂度O(n+m)logn, 空间复杂度O(m)

P4779 【模板】单源最短路径(标准版)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int n, m, s, head[100010], dis[100010], tot;
bool vis[100010];
struct Edge
{
    int next;
    int to;
    int dis;
}edge[200010];    //边数, 无向图要双倍
//链式前向星建图
void add_edge(int u, int v, int w)
{
    tot++;
    edge[tot].dis=w;
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
struct node
{
    int dis;
    int pos;
    //优先队列运算符重载
    bool operator <(const node &x )const
    {
        return dis>x.dis;
    }
};
priority_queue<node> q;
//dijkstra堆优化版
void dijkstra()
{
    dis[s]=0;
    node start;
    start.dis=0;	
    start.pos=s;
    q.push(start);
    while(!q.empty()){
        node tmp=q.top();    //优先队列获取距离源点最近的点
        q.pop();
        int u=tmp.pos;
        if(vis[u])           //如果已经找到最短路了, 已经松弛过了, 就不需要再入队
            continue;
        vis[u]=1;            //标记找到最短路
        //基于u点去松弛与他相连的点
        for(int i=head[u]; i!=0; i=edge[i].next){
            int v=edge[i].to;
            int w=edge[i].dis;
            //如果v点被松弛了, 则把v点的信息入队, 作为下一次最近点的备选项
            if(dis[v]>dis[u]+edge[i].dis){
                dis[v]=dis[u]+w;
                q.push((node){dis[v], v});
            }
        }
    }
}
int main()
{
    scanf("%d %d %d", &n, &m, &s);
    for(int i=1; i<=n; ++i)    dis[i]=INF;
    for(int i=1; i<=m; ++i){
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add_edge(u, v, w);
    }
    dijkstra();
    for(int i=1; i<=n; ++i)
        printf("%d ", dis[i]);
    return 0;
}

二维坐标跑dijkstra堆优化

P4554 小明的游戏

#include <bits/stdc++.h>
using namespace std;
int n, m, ans[520][520], sx, sy, ex, ey;
int mx[5]={0, -1, 1, 0, 0};
int my[5]={0, 0, 0, -1, 1};
char a[520][520];
bool vis[520][520];
struct node
{
	int x, y, dis;
}asd;
bool operator < (node x, node y)
{
	return x.dis>y.dis;
}
priority_queue<node> q;
void dijkstra()
{
	ans[sx][sy]=0;
	q.push({sx, sy, 0});
	while(!q.empty()){
		asd=q.top();
		int x=asd.x;
		int y=asd.y;
		q.pop();
		if(vis[x][y]){
			continue;
		}
		vis[x][y]=true;
		for(int i=1; i<=4; ++i){
			int nx=x+mx[i];
			int ny=y+my[i];
			if(nx>=1 && nx<=n && ny>=1 && ny<=m){
				if(a[nx][ny]==a[x][y] && ans[nx][ny]>ans[x][y]){
					ans[nx][ny]=ans[x][y];
					q.push({nx, ny, ans[nx][ny]});
				}
				else if(a[nx][ny]!=a[x][y] && ans[nx][ny]>ans[x][y]+1){
					ans[nx][ny]=ans[x][y]+1;
					q.push({nx, ny, ans[nx][ny]});
				}
			}
		}
	}
}
int main()
{
	while(1){
		scanf("%d %d", &n, &m);
		if(n==0 && m==0){
			return 0;
		}
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=m; ++j){
				cin >> a[i][j];
			}
		}
		scanf("%d %d %d %d", &sx, &sy, &ex, &ey);
		sx++;	sy++;
		ex++;	ey++;
		memset(ans, 0x3f, sizeof(ans));
		memset(vis, 0, sizeof(vis));
		dijkstra();
		printf("%d\n", ans[ex][ey]);
	}
	return 0;
}

四、dijkstra灵活使用变种

P1396 营救

#include <bits/stdc++.h>
using namespace std;
int n, m, s, t, tot, head[10010], dis[10010]; 
bool vis[10010];
struct Edge 
{
    int nex;
    int to;
    int dis;
}edge[40010];
void add_edge(int u, int v, int w)
{
    tot++;
    edge[tot].to=v;
    edge[tot].dis=w;
    edge[tot].nex=head[u];
    head[u]=tot;
}
struct node 
{
    int id, dis;
    bool operator <(const node &x)const{
        return dis>x.dis;
    }
};
priority_queue<node> q;
void dijkstra()
{
    for(int i=1; i<=n; ++i){
        dis[i]=1000000000;
    }
    dis[s]=0;
    node start;
    start.id=s;
    start.dis=0;
    q.push(start);
    while(!q.empty()){
        node temp=q.top();
        q.pop();
        int u=temp.id;
        if(vis[u]){
            continue;
        }
        vis[u]=true;
        for(int i=head[u]; i; i=edge[i].nex){
            int v=edge[i].to;
            if(max(dis[u], edge[i].dis)<dis[v]){
                dis[v]=max(dis[u], edge[i].dis);
                q.push((node){v, dis[v]});
            }
        }
    }
}
int main()
{
    scanf("%d %d %d %d", &n, &m, &s, &t);
    for(int i=1; i<=m; ++i){
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    dijkstra();
    printf("%d", dis[t]);
    return 0;
}

五、SPFA  时间复杂度O(km), k为每个节点的平均入队次数,空间复杂度O(m)

P3371 【模板】单源最短路径(弱化版)

#include <bits/stdc++.h>
#define INF 2147483647
using namespace std;
int n, m, s, u, v, w, tot, head[10001], dis[10001];
bool vis[10001];
queue<int> q;
struct Edge{
    int next;
    int to;
    int dis;
}edge[500001];
void add_edge(int u, int v, int w)
{
    tot++;
    edge[tot].next=head[u];
    edge[tot].to=v;
    edge[tot].dis=w;
    head[u]=tot;
}
void spfa(int s)
{
    for(int i=1; i<=n; ++i){
	dis[i]=INF;		
        vis[i]=false;
    }
    dis[s]=0;
    //表示s点在队列里
    vis[s]=true;
    q.push(s);
    while(!q.empty()){
	int u=q.front();
	q.pop();
        //出队的同时,将vis标记改为false,表示u不在队列中了
	vis[u]=false;
        //枚举从u点出发的每条边
	for(int i=head[u]; i!=0; i=edge[i].next){
	    int v=edge[i].to;
	    int w=edge[i].dis;
            //通过这条边能够松弛
    	    if(dis[v]>dis[u]+w){
		dis[v]=dis[u]+w;
                //如果被松弛的点v不在队列中, 则v入队
		if(vis[v]==false){
    		    vis[v]=true;    //标记为在队列中
		    q.push(v);
		}
	    }
	}
    }
}
int main()
{
    scanf("%d %d %d", &n, &m, &s);
    for(int i=1; i<=m; ++i){
	scanf("%d %d %d", &u, &v, &w);
	add_edge(u, v, w);
    }
    spfa(s);
    for(int i=1; i<=n; ++i){
	printf("%d ", dis[i]);
    }
    return 0;
}

P2865 [USACO06NOV]Roadblocks G

spfa做次短路

#include <bits/stdc++.h>
using namespace std;
int n, m, dis[5010], cidis[5010], tot, head[5010];
bool vis[5010];
struct edge{
	int to, dis, nex;
}e[200010];
queue<int> q;
void add(int u, int v, int w)
{
	tot++;
	e[tot].to=v;
	e[tot].dis=w;
	e[tot].nex=head[u];
	head[u]=tot;
}
void spfa()
{
	int u, v, w;
	memset(dis, 0x3f, sizeof(dis));
	memset(cidis, 0x3f, sizeof(cidis));
	dis[1]=0;
	vis[1]=true;
	q.push(1);
	while(!q.empty()){
		u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u]; i; i=e[i].nex){
			//u--->v, 边权为w 
			v=e[i].to;
			w=e[i].dis;
			//最短路松弛最短路和次短路 
			if(dis[v]>dis[u]+w){	//经过这条边可以松弛1到v的最短路, 则一定能松弛次短路 
				cidis[v]=dis[v];
				dis[v]=dis[u]+w;
				if(!vis[v]){
					vis[v]=true;
					q.push(v);
				}
			}
			else if(dis[v]<dis[u]+w && cidis[v]>dis[u]+w){		//最短路松弛次短路 
				//经过这条边松弛不了最短路, 但是能松弛次短路, 并且松弛后的次短路不等于最短路 
				cidis[v]=dis[u]+w; 
				if(!vis[v]){
					vis[v]=true;
					q.push(v);
				}
			}
			if(cidis[v]>cidis[u]+w){		//次短路松弛次短路
				cidis[v]=cidis[u]+w; 
				if(!vis[v]){
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
}
int main()
{
	int u, v, w;
	scanf("%d %d", &n, &m);
	while(m--){
		scanf("%d %d %d", &u, &v, &w);
		add(u, v, w);
		add(v, u, w);
	}
	spfa();
	printf("%d", cidis[n]);
	return 0;
}

六、SPFA判断能到达的负环

P3385 【模板】负环

#include<bits/stdc++.h>
using namespace std;
int n,m,dis[3005],tot,head[3005],cnt[3005];
struct Edge{
	int nex,dis,to;
}e[6010];
bool vis[3005],tf;
void add(int u,int v,int w){
	tot++;
	e[tot].dis=w;
	e[tot].nex=head[u];
	e[tot].to=v;
	head[u]=tot;
}
queue<int>q;
void spfa(){
	dis[1]=0;
	q.push(1);
	vis[1]=1;
	while(!q.empty()){
		int pos=q.front();
		q.pop();
		vis[pos]=0;
		for(int i=head[pos];i;i=e[i].nex){
			int v=e[i].to,w=e[i].dis;
			if(dis[v]>dis[pos]+w){
				dis[v]=dis[pos]+w;
				cnt[v]=cnt[pos]+1;
				if(cnt[v]>n){
					cout << "YES" << endl;
					return;
				}
				if(!vis[v]){
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
	cout << "NO" << endl;
}
int main(){
	int t;
	cin >> t;
	while(t--){
		cin >> n >> m;
		memset(dis,0x3f,sizeof(dis));
		memset(vis,0,sizeof(vis));
		memset(head,0,sizeof(head));
		tot=0;
		cnt[1]=1;
		while(!q.empty()){
			q.pop();	
		}
		for(int i=1;i<=m;i++){
			int u,v,w;
			cin >> u >> v >> w;
			add(u,v,w);
			if(w>=0){
				add(v,u,w);	
			}
		}
		spfa();
	}
	return 0;
}

七、分层图最短路

P8724 [蓝桥杯 2020 省 AB3] 限高杆

方法一:dp思想

#include<bits/stdc++.h>
using namespace std;
int n, m, a, b, c, d, head[10010], dis[10010][3], tot;
bool vis[10010][3];
struct node
{
	int id, dis, cnt;
};
bool operator < (node x, node y)
{
	return x.dis>y.dis;
}
priority_queue<node> q;
struct Edge
{
	int to, w, d, nex;
}e[200010];
void add(int u, int v, int w, int d)
{
	tot++;
	e[tot].to=v;
	e[tot].w=w;
	e[tot].d=d;
	e[tot].nex=head[u];
	head[u]=tot;
}
void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[1][0]=0;
	node asd={1, 0, 0};
	q.push(asd);
	while(!q.empty()){
		asd=q.top();
		q.pop();
		int u=asd.id;
		int cnt=asd.cnt;
		if(vis[u][cnt])	continue;
		vis[u][cnt]=true;
		for(int i=head[u]; i; i=e[i].nex){
			int v=e[i].to;
			int w=e[i].w;
			//有杆, 拆了数量没超过2, 更优 
			if(e[i].d && cnt+1<=2 && dis[v][cnt+1]>dis[u][cnt]+w){
				dis[v][cnt+1]=dis[u][cnt]+w;
				q.push({v, dis[v][cnt+1], cnt+1});
			}
			else if(!e[i].d && dis[v][cnt]>dis[u][cnt]+w){	//没杆 
				dis[v][cnt]=dis[u][cnt]+w;
				q.push({v, dis[v][cnt], cnt});
			}
		}
	}
}
int main(){
	scanf("%d %d", &n, &m);
	for(int i=1; i<=m; ++i){
		scanf("%d %d %d %d", &a, &b, &c, &d);
		add(a, b, c, d);
		add(b, a, c, d);
	}
	dijkstra();
	//一个杆也没拆, 最大
	//拆一个或者拆两个,  最小 
	printf("%d", dis[n][0]-min(dis[n][0], min(dis[n][1], dis[n][2])));
	return 0;
}

方法二:建立分层图

P4568 [JLOI2011] 飞行路线

方法一:dp思想

#include <bits/stdc++.h>
using namespace std;
int n, m, k, s, t, a, b, c, dis[10010][12], u, v, w, tot, head[10010], ans=INT_MAX;
bool vis[10010][12];
struct node
{
	int id, curdis, cnt;
}asd;
bool operator < (node x, node y)
{
	if(x.curdis>y.curdis || x.curdis==y.curdis&&x.cnt>y.cnt){
		return true;
	}
	else{
		return false; 
	} 
}
priority_queue<node> q;
struct Node
{
	int to, dis, nex;
}e[100010];
void add(int u, int v, int w)
{
	tot++;
	e[tot].to=v;
	e[tot].dis=w;
	e[tot].nex=head[u];
	head[u]=tot;
}
void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[s][0]=0;
	q.push({s, 0, 0});
	while(!q.empty()){
		asd=q.top();
		u=asd.id;
		int cnt=asd.cnt;	//到当前u已经免费坐了cnt次飞机 
		q.pop();
		if(vis[u][cnt]){
			continue;
		}
		vis[u][cnt]=true;
		for(int i=head[u]; i; i=e[i].nex){
			v=e[i].to;
			w=e[i].dis;
			//免费次数还没达到k, 这次u到v继续免费 
			if(cnt<k && dis[v][cnt+1]>dis[u][cnt]){
				dis[v][cnt+1]=dis[u][cnt];
				q.push({v, dis[v][cnt+1], cnt+1});
			}
			//注意:可以免费也可以不免费
			if(dis[v][cnt]>dis[u][cnt]+w){	//不免费坐 
				dis[v][cnt]=dis[u][cnt]+w;
				q.push({v, dis[v][cnt], cnt});
			}
		}
	}
}
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	scanf("%d %d", &s, &t);
	for(int i=1; i<=m; ++i){
		scanf("%d %d %d", &u, &v, &w);
		add(u, v, w);
		add(v, u, w);		
	}
	dijkstra();
	for(int i=0; i<=k; ++i){
		ans=min(ans, dis[t][i]);
	}
	printf("%d", ans);
	return 0;
}

方法二:建立分层图

P2939 [USACO09FEB]Revamping Trails G

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, k, a, b, c, dis[10010][22], u, v, w, tot, head[10010], ans=LONG_LONG_MAX;
bool vis[10010][22];
struct node
{
	int id, curdis, cnt;
}asd;
bool operator < (node x, node y)
{
	if(x.curdis>y.curdis || x.curdis==y.curdis&&x.cnt>y.cnt){
		return true;
	}
	else{
		return false; 
	} 
}
priority_queue<node> q;
struct Node
{
	int to, dis, nex;
}e[100010];
void add(int u, int v, int w)
{
	tot++;
	e[tot].to=v;
	e[tot].dis=w;
	e[tot].nex=head[u];
	head[u]=tot;
}
void dijkstra()
{
	memset(dis, 0x7f, sizeof(dis));
	dis[1][0]=0;
	q.push({1, 0, 0});
	while(!q.empty()){
		asd=q.top();
		u=asd.id;
		int cnt=asd.cnt;	//到当前u已经免费坐了cnt次飞机 
		q.pop();
		if(vis[u][cnt]){
			continue;
		}
		vis[u][cnt]=true;
		for(int i=head[u]; i; i=e[i].nex){
			v=e[i].to;
			w=e[i].dis;
			//免费次数还没达到k, 这次u到v继续免费 
			if(cnt<k && dis[v][cnt+1]>dis[u][cnt]){
				dis[v][cnt+1]=dis[u][cnt];
				q.push({v, dis[v][cnt+1], cnt+1});
			}
			if(dis[v][cnt]>dis[u][cnt]+w){	//不免费坐 
				dis[v][cnt]=dis[u][cnt]+w;
				q.push({v, dis[v][cnt], cnt});
			}
		}
	}
}
signed main()
{
	scanf("%lld %lld %lld", &n, &m, &k);
	for(int i=1; i<=m; ++i){
		scanf("%lld %lld %lld", &u, &v, &w);
		add(u, v, w);
		add(v, u, w);		
	}
	dijkstra();
	for(int i=0; i<=k; ++i){
		ans=min(ans, dis[n][i]);
	}
	printf("%lld", ans);
	return 0;
}

P4822 [BJWC2012]冻结

#include <bits/stdc++.h>
using namespace std;
int n, m, k, a, b, c, dis[51][51], u, v, w, tot, head[51], ans=INT_MAX;
bool vis[51][51];
struct node
{
	int id, curdis, cnt;
}asd;
bool operator < (node x, node y)
{
	if(x.curdis>y.curdis || x.curdis==y.curdis&&x.cnt>y.cnt){
		return true;
	}
	else{
		return false; 
	} 
}
priority_queue<node> q;
struct Node
{
	int to, dis, nex;
}e[2010];
void add(int u, int v, int w)
{
	tot++;
	e[tot].to=v;
	e[tot].dis=w;
	e[tot].nex=head[u];
	head[u]=tot;
}
void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[1][0]=0;
	q.push({1, 0, 0});
	while(!q.empty()){
		asd=q.top();
		u=asd.id;
		int cnt=asd.cnt;	//到当前u已经用了cnt次SpellCard
		q.pop();
		if(vis[u][cnt]){
			continue;
		}
		vis[u][cnt]=true;
		for(int i=head[u]; i; i=e[i].nex){
			v=e[i].to;
			w=e[i].dis;
			//SpellCard次数还没达到k, 这次u到v继续使用SpellCard 
			if(cnt<k && dis[v][cnt+1]>dis[u][cnt]+w/2){
				dis[v][cnt+1]=dis[u][cnt]+w/2;
				q.push({v, dis[v][cnt+1], cnt+1});
			}
			if(dis[v][cnt]>dis[u][cnt]+w){	//不使用SpellCard 
				dis[v][cnt]=dis[u][cnt]+w;
				q.push({v, dis[v][cnt], cnt});
			}
		}
	}
}
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	for(int i=1; i<=m; ++i){
		scanf("%d %d %d", &u, &v, &w);
		add(u, v, w);
		add(v, u, w);		
	}
	dijkstra();
	for(int i=0; i<=k; ++i){
		ans=min(ans, dis[n][i]);
	}
	printf("%d", ans);
	return 0;
}

P3831 [SHOI2012]回家的路

八、其他最短路题目

P8802 [蓝桥杯 2022 国 B] 出差

灵活双向建图,之后随便跑个最短路

#include <bits/stdc++.h>
using namespace std;
int n, m, c[1010], dis[1010], u, v, w;
struct node
{
	int u, v, w;
}e[20010];
int main()
{
	scanf("%d %d", &n, &m);
	memset(dis, 0x3f, sizeof(dis));
	dis[1]=0;	//起点最短路初始化 
	for(int i=1; i<=n; ++i){
		scanf("%d", &c[i]);
	}
	//从1出发不需要隔离, 但是题目给的c[1]非0 
	c[1]=0; 
	for(int i=1; i<=m; ++i){
		scanf("%d %d %d", &u, &v, &w);
		//从u到v
		//花的时间包含从u出发前隔离的时间c[u]以及路上行走的时间w 
		e[i].u=u;
		e[i].v=v;
		e[i].w=c[u]+w;
		//从v到u
		//花的时间包含从v出发前隔离的时间c[v]以及路上行走的时间w 
		e[i+m].u=v;
		e[i+m].v=u;
		e[i+m].w=c[v]+w;
	}
	//bellman ford
	for(int i=1; i<n; ++i){
		for(int j=1; j<=2*m; ++j){
			u=e[j].u;
			v=e[j].v;
			w=e[j].w;
			dis[v]=min(dis[v], dis[u]+w);
		}
	}
	printf("%d", dis[n]);
	return 0;
}

P8674 [蓝桥杯 2018 国 B] 调手表

#include <bits/stdc++.h>
using namespace std;
int n, k, dis[100010], u, v, ans;
bool vis[100010];
struct node
{
	int id, dis;
}asd;
priority_queue<node> q;
bool operator < (node x, node y)
{
	return x.dis>y.dis;
}
void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[0]=0;
	asd.id=0;
	asd.dis=0;
	q.push(asd);
	while(!q.empty()){
		asd=q.top();
		q.pop();
		u=asd.id;
		if(vis[u]){
			continue;
		}
		vis[u]=true;
		v=u+1;
		if(v==n+1){
			v=0;
		}
		if(v<=n && dis[v]>dis[u]+1){
			dis[v]=dis[u]+1;
			q.push({v, dis[v]});
		}
		v=u+k;
		if(v>n){
			v=v%n-1;
		}
		if(v<=n && dis[v]>dis[u]+1){
			dis[v]=dis[u]+1;
			q.push({v, dis[v]});
		}
	}
}
int main()
{
	scanf("%d %d", &n, &k);
	n--;
	dijkstra();
	for(int i=1; i<=n; ++i){
		ans=max(ans, dis[i]);
	}
	printf("%d", ans);
	return 0;
}

P5651 基础最短路练习题

#include <bits/stdc++.h>
using namespace std;
int n, m, q, x, y, w;
bool vis[100010];
struct node
{
	int to, weight;
};
vector<node> a[100010];
long long dis[100010];
void dfs(int u)
{
	vis[u]=true;
	for(int i=0; i<a[u].size(); ++i){
		int v=a[u][i].to;
		if(!vis[v]){
			dis[v]=dis[u]^a[u][i].weight;
			dfs(v);
		}
	}
}
int main()
{
	scanf("%d %d %d", &n, &m, &q);
	for(int i=1; i<=m; ++i){
		scanf("%d %d %d", &x, &y, &w);
		a[x].push_back({y, w});
		a[y].push_back({x, w});
	}
	//起点固定,不管怎么走, 最后的dis都是一样的, 走一遍求出所有的dis 
	dfs(1);
	while(q--){
		scanf("%d %d", &x, &y);
		//因为dis[y]=dis[x]^ans
		//所以ans=dis[x]^dis[y]; 
		printf("%lld\n", dis[x]^dis[y]);
	}
	return 0;
}

P1744 采购特价商品

#include <bits/stdc++.h>
using namespace std;
int n, m, x, y, s, t;
double dis[110][110], xid[110], yid[110];
double cal(int i, int j)
{
	return sqrt((xid[i]-xid[j])*(xid[i]-xid[j])+(yid[i]-yid[j])*(yid[i]-yid[j]));
}
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=n; ++j){
			dis[i][j]=3000000;
		}
	}
	for(int i=1; i<=n; ++i){
		dis[i][i]=0;
		scanf("%lf %lf", &xid[i], &yid[i]);
	}
	scanf("%d", &m);
	while(m--){
		scanf("%d %d", &x, &y);
		dis[x][y]=min(dis[x][y], cal(x, y));
		dis[y][x]=min(dis[y][x], cal(x, y));
	}
	scanf("%d %d", &s, &t);
	for(int k=1; k<=n; ++k){
		for(int i=1; i<=n; ++i){
			for(int j=1; j<=n; ++j){
				dis[i][j]=min(dis[i][j], dis[i][k]+dis[k][j]);
			}
		}
	}
	printf("%.2lf", dis[s][t]);
	return 0;
}

P1938 [USACO09NOV]Job Hunt S

#include <bits/stdc++.h>
using namespace std;
int n, m, d, p, c, f, s, u, v, w, dis[222], asd, ok[222];
struct node
{
	int u, v, w;
}e[520];
int main()
{
	scanf("%d %d %d %d %d", &d, &p, &c, &f, &s);
	for(int i=1; i<=p; ++i){
		scanf("%d %d", &u, &v);
		m++;
		e[m].u=u;
		e[m].v=v;
		e[m].w=d;
	}
	for(int i=1; i<=f; ++i){
		scanf("%d %d %d", &u, &v, &w);
		m++;
		e[m].u=u;
		e[m].v=v;
		e[m].w=d-w;
	}
	ok[s]=true;		//从s出发能到s
	//可以赊账, 最开始多带220000虚拟钱 
	dis[s]=d+220000;
	for(int i=1; i<=c; ++i){
		for(int j=1; j<=m; ++j){
			u=e[j].u;
			v=e[j].v;
			w=e[j].w;
			if(ok[u]){	//如果能到点u, 避免出现s到不了的负环, 这样也挣不到钱 
				ok[v]=true;
				dis[v]=max(dis[v], dis[u]+w);
			}
		}
	}
	for(int j=1; j<=m; ++j){
		u=e[j].u;
		v=e[j].v;
		w=e[j].w;
		if(ok[u] && dis[v]<dis[u]+w){
			printf("-1");
			return 0;
		}
	}
	for(int i=1; i<=c; ++i){
		asd=max(asd, dis[i]);
	}
	//把最开始带的虚拟钱再减掉 
	printf("%d", asd-220000);
	return 0;
}

P2648 赚钱

#include <bits/stdc++.h>
using namespace std;
int n, m, d, p, c, f, u, v, w, dis[310], asd;
struct node
{
	int u, v, w;
}e[666];
int main()
{
	scanf("%d %d %d %d", &d, &p, &c, &f);
	for(int i=1; i<=p; ++i){
		scanf("%d %d", &u, &v);
		m++;
		e[m].u=u;
		e[m].v=v;
		e[m].w=d;
	}
	for(int i=1; i<=f; ++i){
		scanf("%d %d %d", &u, &v, &w);
		m++;
		e[m].u=u;
		e[m].v=v;
		e[m].w=d-w;
	}
	//可以赊账, 最开始多带300000虚拟钱 
	dis[1]=d+300000;
	for(int i=1; i<=c; ++i){
		for(int j=1; j<=m; ++j){
			u=e[j].u;
			v=e[j].v;
			w=e[j].w;
			dis[v]=max(dis[v], dis[u]+w);
		}
	}
	for(int j=1; j<=m; ++j){
		u=e[j].u;
		v=e[j].v;
		w=e[j].w;
		if(dis[v]<dis[u]+w){
			printf("orz");
			return 0;
		}
	}
	for(int i=1; i<=c; ++i){
		asd=max(asd, dis[i]);
	}
	//把最开始带的虚拟钱再减掉 
	printf("%d", asd-300000);
	return 0;
}

P5905 【模板】Johnson 全源最短路

#include <bits/stdc++.h>
#define INF 0x7f7f7f7f7f7f7f7f
using namespace std;
long long n, m, head[3010], tot, dis[3010], dis1[3010], u, v, w, asd;	
bool vis[3010];
//bellman ford存边 
struct node
{
	long long u, v, w;
}e[9010];
//优先队列元素类型 
struct Node
{
	long long id, dis;
}qtop;
//优先队列小跟堆运算符重载 
bool operator < (Node x, Node y)
{
	return x.dis>y.dis;
}
priority_queue<Node> q;
struct node_edge
{
	long long to, dis, nex;
}E[6010];
//链式前向星存图 
void add(long long u, long long v, long long w)
{
	tot++;
	E[tot].to=v;
	E[tot].dis=w;
	E[tot].nex=head[u];
	head[u]=tot;
}
//Dijkstra堆优化跑最短路 
void dijkstra(long long s)
{
	memset(dis1, 0x7f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	dis1[s]=0;
	qtop={s, 0};
	q.push(qtop);
	while(!q.empty()){
		qtop=q.top();
		q.pop();
		u=qtop.id;
		if(vis[u]){
			continue;
		}
		vis[u]=true;
		for(int i=head[u]; i; i=E[i].nex){
			v=E[i].to;
			w=E[i].dis;
			if(dis1[v]>dis1[u]+w){
				dis1[v]=dis1[u]+w;
				q.push({v, dis1[v]});
			}
		}
	}
}
int main()
{
	scanf("%d %d", &n, &m);
	memset(dis, 0x7f, sizeof(dis));
	dis[0]=0;
	for(int i=1; i<=m; ++i){
		scanf("%lld %lld %lld", &u, &v, &w);
		e[i].u=u;
		e[i].v=v;
		e[i].w=w;
	}
	for(int i=1; i<=n; ++i){
		m++;
		e[m].u=0;
		e[m].v=i;
		e[m].w=0;
	}
	//先bellman ford判断负环 
	for(int i=0; i<=n; ++i){
		for(int j=1; j<=m; ++j){
			u=e[j].u;
			v=e[j].v;
			w=e[j].w;
			dis[v]=min(dis[v], dis[u]+w);
		}
	}
	for(int j=1; j<=m; ++j){
		u=e[j].u;
		v=e[j].v;
		w=e[j].w;
		if(dis[v]>dis[u]+w){
			printf("-1");
			return 0;
		}
	}
	//如果没负环
	//链式前向星存图 
	for(int i=1; i<=m-n; ++i){
		add(e[i].u, e[i].v, e[i].w+dis[e[i].u]-dis[e[i].v]);
	}
	for(long long i=1; i<=n; ++i){
		dijkstra(i);
		asd=0; 
		for(long long j=1; j<=n; ++j){
			if(dis1[j]==INF){
				dis1[j]=1e9;
				asd+=j*dis1[j];
			}
			else{
				asd+=j*(dis1[j]-dis[i]+dis[j]);
			}
		}
		printf("%lld\n", asd);
	}
	return 0;
}

P1948 [USACO08JAN]Telephone Lines S

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值