一.Dijkstra
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
using namespace std ;
const int MAXN = 105 ;
const int INF = 0xfffff ;
struct node{
int p ;
int value ;
friend bool operator < (node a,node b){ //重载;
return a.value > b.value ;
}
};
priority_queue<node> Q ; //优先队列找出最短的那条边;
struct edge{ //静态邻接表之edge
int to ;
int fee ;
int next ;
}edge[MAXN * MAXN] ;
int top ;
int hand[MAXN] ; //静态邻接表之hand
int map[MAXN][MAXN] ;
int dis[MAXN] ;
int vist[MAXN] ;
int path[MAXN] ; //用于储存最小路径的路途;
void addedge(int f,int t,int v){ //静态邻接表之操作;
edge[top].to = t ;
edge[top].fee = v ;
edge[top].next = hand[f] ;
hand[f] = top++ ;
}
void init(int n,int m){ //初始化
int i , j ;
memset(hand,-1,sizeof(hand)) ;
memset(path,-1,sizeof(path)) ;
memset(vist,0,sizeof(vist)) ;
top = 0 ;
while(m--){
int a , b , c ;
scanf("%d%d%d",&a,&b,&c) ;
addedge(a,b,c) ;
addedge(b,a,c) ;
}
for(i = 0 ; i <= n ; i++){
dis[i] = INF ;
}
dis[1] = 0 ;
}
void dijkstra(int n){
while(!Q.empty()) Q.pop() ; //清空队列;
node now ;
now.p = 1 ; //起始点;
now.value = 0 ;
Q.push(now) ;
while(!Q.empty()){
now = Q.top() ;
Q.pop() ;
int u = now.p ;
if(vist[u]) continue ;
vist[u] = 1 ;
int i ;
for(i = hand[u] ; i != -1 ; i = edge[i].next){
int t = edge[i].to ;
if(vist[t]) continue ;
int v = edge[i].fee ;
if(dis[u] + v < dis[t]){
dis[t] = dis[u] + v ;
node next ;
next.p = t ;
next.value = dis[t] ;
Q.push(next) ;
path[t]=u;
}
}
}
}
int main(){
int n , m ;
int i ;
int ans[MAXN] ;
while(scanf("%d%d",&n,&m) != EOF){
if(n == 0 && m == 0) break ;
init(n,m) ;
dijkstra(n) ;
printf("%d\n",dis[n]) ;
int t = 0 ;
for(i = n ; i != -1 ; i = path[i]){
ans[t++] = i ;
}
i=t-1;
printf("%d",ans[i--]);
for(; i >= 0 ; i--){
printf(" %d",ans[i]) ;
}
printf("\n") ;
}
return 0 ;
}
和最小生成树的prim()如出一辙。
关键在于能一个点一个点和一条边一条边的确定下来。
例题
HDU 1535 在一个有向图中,一个点到其他n-1个点来回的最短路径之和;也可以用flody,但是后者要求n在300左右。
二.spfa
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
using namespace std ;
const int MAXN = 105 ;
const int INF = 0xfffff ;
queue<int> q ;
struct edge{ //静态邻接表之edge
int to ;
int fee ;
int next ;
}edge[MAXN * MAXN] ;
int top ;
int hand[MAXN] ; //静态邻接表之hand
int cout[MAXN];
int map[MAXN][MAXN] ;
int dis[MAXN] ;
int path[MAXN] ; //用于储存最小路径的路途;
int flag=0;
void addedge(int f,int t,int v){ //静态邻接表之操作;
edge[top].to = t ;
edge[top].fee = v ;
edge[top].next = hand[f] ;
hand[f] = top++ ;
}
void init(int n,int m){ //初始化
int i ;
memset(hand,-1,sizeof(hand)) ;
memset(path,-1,sizeof(path)) ;
memset(cout,0,sizeof(cout));
top = 0 ;
while(m--){
int a , b , c ;
scanf("%d%d%d",&a,&b,&c) ;
addedge(a,b,c) ;
addedge(b,a,c) ;
}
for(i = 0 ; i <= n ; i++){
dis[i] = INF ;
}
dis[1] = 0 ;
}
void spfa(int n)
{
int inqueue[MAXN] ;
memset(inqueue,0,sizeof(inqueue)) ;
int now = 1 ;
q.push(1) ;
cout[1]++;
inqueue[1] = 1 ;
while(!q.empty())
{
now = q.front() ;
q.pop() ;
inqueue[now] = 0 ;
int i ;
for(i = hand[now] ; i != -1 ; i = edge[i].next)
{
int t = edge[i].to ;
int value = edge[i].fee ;
if(dis[now] + value < dis[t])
{
dis[t] = dis[now] + value ;
path[t] = now ;
if(!inqueue[t]) //一旦dis[t]更新了就要压入队列;
{
q.push(t) ;
cout[t]++; //累计进队列的t的次数;
inqueue[t] = 1 ;
if(cout[t]>n) flag=1; //表示有负环;
}
}
}
}
}
int main(){
int n , m ;
int i ;
int ans[MAXN] ;
while(scanf("%d%d",&n,&m) != EOF){
if(n == 0 && m == 0) break ;
init(n,m) ;
spfa(n) ;
printf("%d\n",dis[n]) ;
int t = 0 ;
for(i = n ; i != -1 ; i = path[i]){
ans[t++] = i ;
}
i=t-1;
printf("%d",ans[i--]);
for(; i >= 0 ; i--){
printf(" %d",ans[i]) ;
}
printf("\n") ;
}
return 0 ;
}
例题
POJ 1613 权值未时间,而通过每条路又有时间规定,不能把最小边确定下来,所以不能用Dijkstra。还有输入要注意,不然会TLE;
HDU 2489 负环问题,只能用spfa,也是因为不能把最小边确定下来;判断是否出现负环,用一个cout数组累计进入队列的i,cont[ i ]大于n就是有负环;
三.Flody
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <queue>
using namespace std ;
const int MAXN = 105 ;
const int INF = 0xfffff ;
int map[MAXN][MAXN] ;
void init(int n,int m){
int i , j ;
for(i = 1 ; i <= n ; i++){
for(j = 1 ; j <= n ; j++){
map[i][j] = INF ;
}
}
while(m--){
int a , b , c ;
scanf("%d%d%d",&a,&b,&c) ;
if(map[a][b] < c) continue ;
map[a][b] = map[b][a] = c ;
}
}
void floyd(int n){
int i , j , k ;
for(k = 1 ; k <= n ; k++){
for(i = 1 ; i <= n ; i++){
for(j = 1 ; j <= n ; j++){
if(i != j && j != k && i != k && map[i][j] > (map[i][k] + map[k][j]))
map[i][j] = map[i][k] + map[k][j] ;
}
}
}
}
int main(){
int n , m ;
int i ;
int ans[MAXN] ;
while(scanf("%d%d",&n,&m) != EOF){
if(n == 0 && m == 0) break ;
init(n,m) ;
floyd(n) ;
printf("%d\n",map[1][n]) ;
}
return 0 ;
}
例题
HDU 1217 map映射+flody;