最短路总结

朴素最短路。

hdoj 2544 最短路  

告诉你图的点,和拥有的边,求两点最短路。我们只要把图存到邻接表或者邻接矩阵中,然后用dijkstra或者spfa来操作这个矩阵就可以得到起点到终点的最短路了。

spfa:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 100000000
using namespace std;

int len[102], mp[102][102];
int adjmp[102][102];
int n, m;


void Read(int &a){
    char ch;
    a = 0;
    ch = getchar();
    while( !(ch >= '0' && ch <= '9') ) ch = getchar();
    while((ch >= '0' && ch <= '9') ){
        a = a * 10 + ch - '0';
        ch = getchar();
    }
}



void init(){
    int i, j;
    int a, b, c;
    memset(mp, 0, sizeof(mp));
    memset(len, 0, sizeof(len));

    for(i=0; i<m; ++i){
        Read(a);
        Read(b);
        Read(c);
        adjmp[a][len[a]++] = b;
        adjmp[b][len[b]++] = a;
        mp[a][b] = mp[b][a] = c;
    }
}



void spfa(){
    int i, j, u, v;
    int MinDis[102];
    bool mark[102];
    queue<int> Q;
    memset(mark, 0, sizeof(mark));
    for(i=0; i<102; ++i) MinDis[i] = inf;
    MinDis[1] = 0;
    Q.push(1);
    mark[1] = 1;
    while(!Q.empty()){
        u = Q.front();
        Q.pop();
        for(i=0; i<len[u]; ++i){
            v = adjmp[u][i];
            if(MinDis[v] > MinDis[u] + mp[u][v]){
                MinDis[v] = MinDis[u] + mp[u][v];
                if(!mark[v]){
                    Q.push(v);
                }
            }
        }
    }

    printf("%d\n", MinDis[n]);
}


int main(){
//    freopen("c:/aaa.txt", "r", stdin);
    while(scanf("%d %d", &n, &m)!=EOF){
        if(n==0 && m==0) break;
        init();
        spfa();
    }
    return 0;
}

dijkstra:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int mp[110][110];
int n, m;
const int inf = 999999999;

void init(){
    int i, j, a, b, c;
    for(i=1; i<=n; ++i){
        for(j=1; j<=n; ++j){
            mp[i][j] = inf;
        }
    }

    for(i=1; i<=m; ++i){
        scanf("%d %d %d", &a, &b, &c);
        if(c < mp[a][b]) mp[a][b] = mp[b][a] = c;
    }
}


void dijkstra(){
    int i, j;
    int dis[110], min, v, total;
    bool mark[110];

    for(i=1; i<=n; ++i){
        dis[i] = mp[1][i];
        mark[i] = 0;
    }

    dis[1] = 0;
    mark[1] = 1;
    total = 0;
    for(i=1; i<n; ++i){
        min = inf;
        for(j=1; j<=n; ++j){
            if(!mark[j] && dis[j] < min){
                min = dis[j];
                v = j;
            }
        }

        mark[v] = 1;
        total += min;
        for(j=1; j<=n; ++j){
            if(!mark[j] && dis[j] > min + mp[j][v]){
                dis[j] = min + mp[j][v];
            }
        }
    }
    printf("%d\n", dis[n]);
}

int main(){
//    freopen("c:/aaa.txt", "r", stdin);
    while(scanf("%d %d", &n, &m)!=EOF){
        if(n==0 && m==0) break;
        init();
        dijkstra();
    }
    return 0;
}

 变形一:边加一个花费属性,求在满足最短路的情况下,使得花费也最短。

hdoj 3790 最短路径问题

在运用算法时,先保证路径长度最短,然后再保证花费最短。

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

typedef __int64 lld;

struct Node {
    lld distance, cost;
};

lld inf = 0xffffffff;
int n, m, s, t;
Node f[1005][1005];
vector<int> vec[1005];
lld Mind[1005], Minc[1005];


void spfa() {
    int i, u, v, sz;    
    bool mark[1050];
    queue<int> Q;
    for( i=1; i<=n; ++i ) {
        Mind[i] = inf;
        Minc[i] = inf;
        mark[i] = 0;
    }
	
    Q.push( s );
    mark[s] = 1;
    Mind[s] = Minc[s] = 0;
    while( !Q.empty() ) {
        u = Q.front();
        Q.pop();
        mark[u] = 0;
        sz = vec[u].size();
        for( i=0; i<sz; ++i ) {
            v = vec[u][i];
            if( Mind[v] > Mind[u] + f[u][v].distance) {
                Mind[v] = Mind[u] + f[u][v].distance;
                Minc[v] = Minc[u] + f[u][v].cost;
                if( !mark[v] ) {
                    mark[v] = 1;
                    Q.push(v);
                }
            } else if( Mind[v] == Mind[u] + f[u][v].distance && Minc[v] > Minc[u] + f[u][v].cost ) {
                Minc[v] = Minc[u] + f[u][v].cost;
                if( !mark[v] ) {
                    mark[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
}


int main() {
	//    freopen( "c:/aaa.txt", "r", stdin);
    int i, j, a, b, c, d;
    while( scanf( "%d %d", &n, &m ) == 2 ) {
        if( n == 0 && m == 0 ) break;
        for( i=1; i<=n; ++i ) {
            vec[i].clear();
            for( j=1; j<=n; ++j ) {
                f[i][j].distance = f[i][j].cost = inf;
            }
        }
		
        for( i=1; i<=m; ++i ) {
            scanf( "%d %d %d %d", &a, &b, &c, &d );
            vec[a].push_back( b );
            vec[b].push_back( a );
            if( c < f[a][b].distance ) {
                f[a][b].distance = f[b][a].distance = c;
                f[a][b].cost = f[b][a].cost = d;
            } else if( c == f[a][b].distance && d < f[a][b].cost ) f[a][b].cost = f[b][a].cost = d;
        }
		
        scanf( "%d %d", &s, &t );
        spfa();
        printf( "%I64d %I64d\n", Mind[t], Minc[t] );
    }
    return 0;
}

变形二:图中每个点有个权值,边没有权值,求从起点到终点路线中,各点权值累加和最大。并输出路径。

这里涉及到将点的权值转换为边的权值,例如:点a的权值为x,存在一条边e( b -> a ),则边e的权值为a的权值。 然后求最短路。

在求路径时:

如果用Floyd算法的话,用一个二维数组path[][]保存路径,并初始化为指定的空值,在递归输出路径时如果碰到空值,就证明输出结束。具体的做法是这样的,比如我们可以初始化为path[a][b] = -1,经过最短路算法后,path[a][b] = c,表明从a到b中要经过c,而且c->b是最后一步,即a->.....->b->c。

如果用spfa的话,路径的保存用一维的数组就可以了,path[]。path[a] = b,表明有条边b->a,即a的父亲为b。

hdoj 1224 Free DIY Tour

code :

Floyd 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;


const int maxn = 105;
int n, mp[maxn][maxn], path[maxn][maxn], val[maxn], ca=1;


void init() {
    int i, j, m;
    scanf( "%d", &n );
    for( i=1; i<=n; ++i ) scanf( "%d", &val[i] );
    val[++n] = 0;
    
    for( i=1; i<=n; ++i ) {
        for( j=1; j<=n; ++j ) {
            mp[i][j] = -1;
            path[i][j] = -1;
        }
    }
	
    scanf( "%d", &m );
    while( m-- ) {
        int a, b;
        scanf( "%d %d", &a, &b );
        if( mp[a][b] + 1 ) continue;
        mp[a][b] = val[b];
    }
}


void Print( int s, int e ) {
    if( path[s][e] + 1 == 0 ) {
        printf( "%d->%d", s, e );
        return;
    }
    Print( s, path[s][e] );
    printf( "->%d", e == n ? 1 : e );
}




void solve() {
    int i, j, k;
    for( k=1; k<=n; ++k ) {
        for( i=1; i<=k; ++i ) {
            for( j=k; j<=n; ++j ) {
                if( mp[i][k]+1 && mp[k][j]+1 && mp[i][k]+mp[k][j] > mp[i][j] ) {
                    mp[i][j] = mp[i][k]+mp[k][j];
                    path[i][j] = k;
                }
            }
        }
    }
	
    if( ca != 1 ) printf( "\n" );
    printf( "CASE %d#\npoints : %d\n", ca++, mp[1][n] );
    printf( "circuit : " );
    Print( 1, n );
    printf( "\n" );
}



int main() {
	//    freopen( "c:/aaa.txt", "r", stdin );
    int T;
    scanf( "%d", &T );
    while( T-- ) {
        init();
        solve();
    }
    return 0;
}

 spfa:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;


const int maxn = 105;
int n, mp[maxn][maxn], val[maxn], ca=1;
int path[maxn];


void init() {
    int i, j, m;
    scanf( "%d", &n );
    for( i=1; i<=n; ++i ) scanf( "%d", &val[i] );
    val[++n] = 0;
    
    for( i=1; i<=n; ++i ) {
        for( j=1; j<=n; ++j ) {
            mp[i][j] = -1;
        }
    }

    scanf( "%d", &m );
    while( m-- ) {
        int a, b;
        scanf( "%d %d", &a, &b );
        if( mp[a][b] + 1 ) continue;
        mp[a][b] = val[b];
    }
}



void Print( int e ) {
    if( e == 1 ) {
        printf( "1" );
        return;
    }
    Print( path[e] );
    printf( "->%d", e == n ? 1 : e );
}


void solve() {
    queue<int> Q;
    bool mark[maxn];
    int Max[maxn], i, u;
    for( i=1; i<=n; ++i ) {
        mark[i] = 0;
        Max[i] = -1;
        path[i] = i;
    }

    Max[1] = 0;
    Q.push( 1 );
    mark[1] = 1;
    while( !Q.empty() ) {
        u = Q.front();
        Q.pop();
        mark[u] = 0;
        for( i=1; i<=n; ++i ) {
            if( mp[u][i]+1 && mp[u][i]+Max[u]>Max[i] ) {
                Max[i] = mp[u][i]+Max[u];
                path[i] = u;
                if( !mark[i] ) {
                    Q.push( i );
                    mark[i] = 1;
                }
            }
        }
    }


    if( ca != 1 ) printf( "\n" );
    printf( "CASE %d#\npoints : %d\n", ca++, Max[n] );
    printf( "circuit : " );
    Print( n );
    printf( "\n" );
}



int main() {
//    freopen( "c:/aaa.txt", "r", stdin );
    int T;
    scanf( "%d", &T );
    while( T-- ) {
        init();
        solve();
    }
    return 0;
}

两个注意的地方:

1.根据求最短路或者最长路,将图的邻接表初始化相应的极限值,求最短路则初始化最大,求最长路初始化为最小指,一般如果不存在负边,我们可以初始化为-1.

2.要考虑是否存在重边的情况。

.

posted on 2011-03-25 18:00  CrazyAC  阅读(498)  评论(0编辑  收藏  举报