zhangas

Pay more attention

0%

图论 最短路问题

dijkstra 所有边权都是正数

朴素版 O(n^2)

n:节点个数
m:边的个数

n^2~m (同一数量级)
稠密图: 用邻接矩阵存储d[t][j]表示从t到j的权重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int g[N][N];//权重
int dist[N];//到一号点的距离
bool st[N];//表示哪些点的最短距离已经确定
void dijkstra(){
memset(dist,0x3f,sizeof(dist));
dist[1]=0;//初始化一号点的距离为0

for(int i=1;i<=n;i++){
int t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(dist[t]>dist[j||t==-1])){
t=j;
}
}

st[t]=true;//最短距离已经确定

for(int j=1;j<=n;j++){
if(dist[j]>dist[t]+g[t][j]){
dist[j]=dist[t]+g[t][j];
}
}
}
}
int main(){
cin>>n>>m;
memset(g,0x3f,sizeof(g));
//读入的时候 存在重边 和自环
while(m--){
cin>>x>>y>>z;
g[x][y]=min(g[x][y],z);//取长度最短的边
}
dijkstra();


}

堆优化版O(m*logn)

n~m (同一数量级)
稀疏图: 用邻接表存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int h[N],e[N],ne[N],w[N],idx;
int n,m,s;
void add(int a,int b,int c){
e[idx]=b;
w[dix]=c;//权重为c
ne[a]=h[a];
h[a]=idx++;
}
//拓展 遍历每个节点的出度
void dijkstra(){
memset(dist,0x3f,sizeof(dist));
priority_queue<PII,vector<PII>,greater<PII>> heap;
//PII: distance 序号
heap.push({0,s});
dist[s]=0

while(heap.size()){
int t=heap.top();
heap.pop();

int distance=t.first,ver=t.second;

if(st[ver])continue;

st[ver]=true;

for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i],c=w[i];
if(dist[j]>distance+c){
dist[j]=distance+c;
heap.push({dist[j],j});
}
}
}

}
int main(){
//链表初始化
memset(h,-1,sizeof(-1));

cin>>n>>m>>s;
int a,b,c;
while(m--){
cin>>a>>b>>c;
add(a,b,c);
}
dijkstra();

for(int i=1;i<=n;i++){
cout<<dist[i]<<" ";
}

return 0;
}

Bellman_Ford

利用结构体存储 O(n*m)

松弛操作
两层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//N为最大节点的个数
int n,m,a,b,w;
int dist[N];//存储到第一节点的距离
int backup[N];
struct Egde{
int a,int b,int w;
}edges[M];//M为最大边数
void bellman_ford(){
memset(dist,-1,sizeof(dist));
for(int i=0;i<k;i++){//题干中最大步数k
memcpy(backup,dist,sizeof(dist));
for(int j=1;j<=m;j++){//开始拓展
int a=edges[j].a,b=edges[j].b,w=edges[j].w;
dist[b]=min(dist[b],backup[a]+w);
}
}
}
//主函数
cin>>n>>m>>k;
for(int i=0;i<m;i++){
cin>>a>>b>>w;
edges[i]={a,b,w};
}
bellman_ford();
if(dist[n]>0x3f3f3f3f/2){//为什么不是0x3f3f3f3f3f呢
//存在负权时 (+∞-w)<+∞ dist[]的值可能会被更新为比+∞小一点的数
cout<<"impossible"<<endl;
}
else{
cout<<dist[n];
}

目的是实现三角不等式即

1
dist[b]<=dist[a]+w;

SPFA

利用BFS优化松弛操作 O(m)~O(n*m)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const int N=1e5+5;
int e[N],ne[N],w[N],h[N],idx;
int add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void spfa(){
memset(dist,0x3f,sizeof(dist));
queue<int>q;
q.push(1);

dist[1]=0;
st[1]=true;

while(q.size()){
int t=q.front();
q.pop();

st[t]=false;

for(int i=h[t];i!=-1;i=ne[i]){
int j=ne[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
}
int main(){
memset(h,-1,sizeof(h));
//省略输入...

if(dist[n]==0x3f3f3f3f){
cout<<"impossible<<ednl;
}
else{
cout<<dist[n]<<endl;
}
return 0;
}

可以用来判断是否存在重环和自环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void spfa(){
queue<int>q;
for(int i=1;i<=n;i++){
q.push(i);
st[i]=true;
}

while(q.size()){
int t=q.front();
q.pop();

st[t]=false;
}
return false;
}

Floyd

邻接矩阵存储 不能出现负权回路 O(n^3)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const int INF=1e9;
int n,m,k;//n是节点的个数 m是边数
int a,b,w;
int g[N][N];
void floyd(){
for(int k=1;k<=n;k++){//寻找i和j之间的节点 且满足经过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]);
}
}
}
}
int main(){
//初始化
cin>>n>>m>>k;
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;
}
}
}
//输入操作

while(m--){
cin>>a>>b>>w;
//重边保留边权最小的
g[a][b]=min(g[a][b],w);
}

floyd();
//处理数据
while(k--){
cin>>a>>b;
//出现负权边 可能更新距离后比INF略小
if(g[a][b]>=INF/2){
cout<<"impossible"<<endl;
}
else{
cout<<g[a][b]<<endl;
}
}
return 0;
}