一、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;
}