hdu 2544

 
 1 最短路
 2 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
 3 Total Submission(s): 98085    Accepted Submission(s): 42348
 4 
 5 
 6 Problem Description
 7 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
 8 
 9  
10 
11 Input
12 输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
13 输入保证至少存在1条商店到赛场的路线。
14  
15 
16 Output
17 对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
18  
19 
20 Sample Input
21 2 1
22 1 2 3
23 3 3
24 1 2 5
25 2 3 5
26 3 1 2
27 0 0
28  
29 
30 Sample Output
31 3
32 2
33  
34 
35 Source

 

 

 

dijkstra算法不能解决负边权的问题

   原因:Dijkstra算法在运行过程中维持的关键信息是一组节点集合S,从源节点s到该集合中每个节点之间的最短路径已经被找到。算法重复从节点集合V-S中选择最短路径估计最小的节点u,将u加入到集合S,然后对所有从u出发的边进行松弛操作。


当把一个节点选入集合S时,即意味着已经找到了从源点到这个点的最短路径,但若存在负权边,就与这个前提矛盾,可能会出现得出的距离加上负权后比已经得到S中的最短路径还短。(无法回溯)

无向图 可以采用dijkstra算法

floyed算法可以解决负边权问题 但是算法效率比较低效 


spfa算法也可以解决负边权问题 效率也比folyed算法要高得多,因为点可能不止一次被压入队列
为了避免最坏情况的出现,在正权图上应使用效率更高的Dijkstra算法
只要最短路径存在,上述SPFA算法必定能求出最小值。
证明:每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点v的最短路径估计值d[v]变小。所以算法的执行会使d越来越小。
由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的逐渐变小,直到到达最短路径值时,算法结束,
这时的最短路径估计值就是对应结点的最短路径值。

实际上,如果一个点进入队列达到n次,则表明图中存在负环,没有最短路径。

 由于用了队列来存储,只要发生了更新就会不断的入队,因此假如有负权回路请你不要用SPFA否则会死循环(然而我们可以用spfa来判断是否存在负权回路)

求负环的常用方法,基于SPFA:

1统计每个点入队的次数,如果某个点入队n次,则说明存在负环;
2统计当前每个点的最短路中所包含的边数即路径长度,如果某点的最短路所包含的边数大于等于n,则说明存在环。
用spfa判断负环,只需要在spfa求最短路的基础上维护一个cnt数组,cnt[i] = j:表示从源点到顶点i经过的边数是j。
https://blog.csdn.net/HangHug_L/article/details/113996364 存在负环的条件:cnt[x]
>= n,意味着1~x经过了n条边,n+1个点,而图中只有n个点,所以n+1个点中至少有一个点出现了两次,即存在环,要想使得距离更小,环只能是负环。

 

 1 //dijk 算法 (单源)
 2 
 3 #include <iostream>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cstring>
 7 #include <iostream>
 8 #include <algorithm>
 9 #include <cmath>
10 #include <queue>
11 #include <set> 
12 #include <map>
13 using namespace std;
14 #define  pi acos(-1.0)
15 #define ll long long 
16 int n,m;
17 int a,b,c;
18 const int N  =150;
19 int g[N][N],d[N];
20 const int inf = 0x3f3f3f3f;
21 bool vis[N];
22 void init()
23 {
24     for(int i=0;i<N;i++){
25         for(int j=0;j<N;j++){
26             if(i==j) g[i][j]=0;
27             else g[i][j]=inf;
28         }
29         d[i]=inf;
30     }
31     memset(vis,0,sizeof(vis));
32 }
33 void  dijk(int s,int e,int n){
34     d[s]=0;
35     for(int i=0;i<n-1;i++){//每次找出一个s到一个点的最短距离,因此至少n-1次循环 
36         int minn,min_num;
37         minn=inf;
38         for(int j=1;j<=n;j++){    
39             if(minn>d[j]&&!vis[j]){
40                 minn=d[j];
41                 min_num=j;
42             }
43         }
44         vis[min_num]=1;
45         for(int k=1;k<=n;k++){
46             if(!vis[k]&&d[k]>d[min_num]+g[min_num][k]){
47                 d[k]=d[min_num]+g[min_num][k];
48             }
49         }
50     }
51 }
52 int main()
53 {
54     while(~scanf("%d%d",&n,&m)){
55         if(n==0&&m==0) break;
56         init();
57         for(int i=0;i<m;i++){
58             scanf("%d%d%d",&a,&b,&c);
59             g[a][b]=g[b][a]=c;
60         }
61         dijk(1,n,n);
62         printf("%d\n",d[n]);
63     }
64     return 0;
65 }

 

 

// https://blog.csdn.net/hahahahahaha5/article/details/118765992
import java.util.*;
// Dijkstra
// public class ZuiduanLu {
// static int d[];
// static int g[][];
// static int vis[];
// static int n, m;

// public static void init(int n) {
// for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= n; j++) {
// if (i == j)
// g[i][j] = 0;
// g[i][j] = Integer.MAX_VALUE;
// }
// d[i] = Integer.MAX_VALUE;
// vis[i] = 0;

// }

// }

// public static void dijkstra(int s, int n) { // O(n^2) O(n^2)
// d[s] = 0;

// for (int i = 0; i < n; i++) {

// int minn = Integer.MAX_VALUE, min_num = s;
// for (int j = 1; j <= n; j++) {
// if (vis[j] == 0 && d[j] < minn) {
// minn = d[j];
// min_num = j;
// }
// }
// vis[min_num] = 1;
// for (int j = 1; j <= n; j++) {
// if (vis[j] == 0 && d[j] > d[min_num] + g[min_num][j]) {
// d[j] = d[min_num] + g[min_num][j];
// }
// }
// }
// }

//
// public static void main(String[] args) {
// Scanner in = new Scanner(System.in);
// n = in.nextInt();
// m = in.nextInt();
// d = new int[n + 1];
// g = new int[n + 1][n + 1];
// vis = new int[n + 1];
// init(n);
// for (int i = 0; i < m; i++) {
// int a = in.nextInt();
// int b = in.nextInt();
// int val = in.nextInt();
// g[a][b] = val;
// g[b][a] = val;
// }
// dijkstra(1, n);
// for (int i = 1; i <= n; i++) {
// System.out.print(d[i]);
// }
// System.out.println();

// }
// }
Dijkstra+heap 优化
public class ZuiduanLu {
static int d[];
static int g[][];

static int n, m;

static class Node {
int id, val;

public Node(int id, int val) {
this.id = id;
this.val = val;
}
}

static class compa implements Comparator<Node> {
@Override
public int compare(Node x, Node y) {
return x.val - y.val;
}

}

// 不要设置为 Integer.MAX_VALUE 会溢出
public static void init(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if(i==j) g[i][j] =0;
g[i][j] = 1234555;
}
d[i] = 1234555;

}

}

// e 边数目 v 顶点数目
public static void dijkstra(int s, int n) { // O((e+v)log(v)) O(n^2)
d[s] = 0;

Queue<Node> que = new PriorityQueue<>(new compa());
que.offer(new Node(s, d[s]));
while (!que.isEmpty()) {
Node tmp = que.poll();

int min_num = tmp.id;
int dval = tmp.val;
// if (dval > d[min_num])
// continue;

for (int j = 1; j <= n; j++) {
if (d[j] > dval + g[min_num][j]) {
d[j] = dval + g[min_num][j];
que.offer(new Node(j, d[j]));
}
}

}

}


public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
d = new int[n + 1];
g = new int[n + 1][n + 1];

init(n);
for (int i = 0; i < m; i++) {
int a = in.nextInt();
int b = in.nextInt();
int val = in.nextInt();
g[a][b] = val;
g[b][a] = val;
}
dijkstra(1, n);
for (int i = 1; i <= n; i++) {
System.out.print(d[i]);
}
System.out.println();

}
}

 

 

 

//flord  算法(多源)
//https://blog.csdn.net/amazingcode/article/details/53038977  挺好的
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set> 
#include <map>
using namespace std;
#define  pi acos(-1.0)
#define ll long long 
int n,m;
int a,b,c;
const int N  =150;
int f[N][N];
const int inf  = 0x3f3f3f3f;
void  init()
{
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(i==j)  f[i][j]= 0;
            else{
                f[i][j] = inf;
            }
        }
    }
}
int  main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break;
        init();
        for(int i=0;i<m;i++)
        {
              scanf("%d%d%d",&a,&b,&c);
              f[a][b]=f[b][a]=c;            
        }
        for(int k=1;k<=n;k++){//k  在最外层
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
                }
            }
        }
        printf("%d\n",f[1][n]);
    }
    return 0;
 } 

 

 

 spfa在最优的情况下是O(kE),就是遍历了一遍所有的边。 最坏:O(VE)

 1 /*
 2 算法原理
 3 这个算法因为与贝尔曼福德(Bellman-Ford)算法比较相似,只是在它的算法的基础上进行了队列优化,因此也被嘲讽为“队列优化的贝尔曼福德”。
 4 
 5 就是每次可以更新到一个节点的最短距离的时候,我们就更新它,并更新所有它能到达的子节点,直到没有节点需要被更新。
 6 
 7 */
 8 //spfa  单源
 9 #include <iostream>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #include <cmath>
16 #include <queue>
17 #include <set> 
18 #include <map>
19 using namespace std;
20 #define  pi acos(-1.0)
21 #define ll long long 
22 int n,m;
23 int a,b,c;
24 const int N  =150;
25 int d[N],f[N][N],cnt[N];
26 const int inf  =0x3f3f3f3f;
27 bool vis[N];
28 void init()
29 {
30     for(int i =0;i<N;i++){
31         for(int j=0;j<N;j++){
32             f[i][j]=(i==j)?0:inf;
33         }
34         d[i] = inf ;
35         vis[i] = 0;
cnt[i] = 0;
36 } 37 38 } 39 void spfa(int st) 40 { 41 d[st] = 0; 42 queue<int>Q; 43 while(!Q.empty()) Q.pop(); 44 Q.push(st); 45 vis[st] =1; 46 while(!Q.empty()){ 47 int u =Q.front(); 48 Q.pop(); 49 vis[u] =0; 50 for(int i =1;i<=n;i++){ 51 if(d[i]>d[u]+f[u][i]){ 52 d[i] = d[u] +f[u][i]; 53 if(!vis[i]){ 54 vis[i] = 1; 55 Q.push(i); 56 }
cnt[i] =cnt[u]+1;
if(cnt[i]>=n) 存在负环
57 } 58 } 59 } 60 } 61 int main() 62 { 63 while(~scanf("%d%d",&n,&m)&&(n+m)){ 64 init(); 65 for(int i=0;i<m;i++){ 66 scanf("%d%d%d",&a,&b,&c); 67 f[a][b] = f[b][a] = c; 68 } 69 spfa(1); 70 printf("%d\n",d[n]); 71 } 72 return 0; 73 }

 

------------恢复内容结束------------

posted on 2019-03-13 22:42  cltt  阅读(165)  评论(0编辑  收藏  举报

导航