poj 1122 最短路+路径追踪(消防路径)

题意:在一个n顶点图上,找出从消防站到着火点的最短时间与最短时间中所走的点。路的长度由一个n×n的矩阵给出,矩阵中的第(i,j)个元素代表从i到j的时间,-1代表不能到达。最后一行,第一个数代表着火点;后面多个数代表消防站。输出的是消防站 着火点 时间 路径,按照时间从小到大排序输出(如果有相同的则任意输出,如果有不同的路径也是任意输出)。

思路:非常显然的最短路,不过是多源点单汇点,这个可以通过将每个边反向建图来求。鉴于顶点数限制非常小(n<=20),所以dijkstra、spfa、floyd都可以用,需要注意Floyd的路径追踪方式,对于pre[i][j] = k的讨论。

dijkstra:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3fffffff
#define N 25
int dis[N],pre[N],first[N],used[N];
int n,top,len = 0,start;
struct res{
    int id,dist;
}p[N];
struct edge{
    int y,w,next;
}e[N*N];
void add(int x,int y,int w){
    e[top].y = y;
    e[top].w = w;
    e[top].next = first[x];
    first[x] = top++;
}
int cmp(struct res a,struct res b){
    return a.dist < b.dist;
}
void dijkstra(){
    int i,j,min,now=0;
    for(i = 1;i<=n;i++)
        dis[i] = INF;
    dis[start] = 0;
    memset(used, 0, sizeof(used));
    for(i = 1;i<=n;i++){
        min = INF;
        for(j = 1;j<=n;j++)
            if(!used[j] && dis[j]<min){
                min = dis[j];
                now = j;
            }
        used[now] = 1;
        for(j = first[now];j!=-1;j=e[j].next)
            if(!used[e[j].y] && dis[now]+e[j].w < dis[e[j].y]){
                dis[e[j].y] = dis[now]+e[j].w;
                pre[e[j].y] = now;
            }
    }
}
void print_dist(int x){
    while(x){
        printf("\t%d",x);
        x = pre[x];
    }
    putchar('\n');
}
void print(){
    int i;
    for(i = 0;i<len;i++)
        p[i].dist = dis[p[i].id];
    sort(p, p+len, cmp);                //按照需要输出的点得路径排序
    printf("Org\tDest\tTime\tPath\n");
    for(i = 0;i<len;i++){
        printf("%d\t%d\t%d",p[i].id,start,p[i].dist);
        print_dist(p[i].id);
    }
}
int main(){
    int i,j,w;
    scanf("%d",&n);
    memset(first, -1, sizeof(first));
    top = 0;
    for(i = 1;i<=n;i++)
        for(j = 1;j<=n;j++){
            scanf("%d",&w);
            if(w!=-1)
                add(j,i,w);
        }
    scanf("%d",&start);
    while(scanf("%d",&j) !=EOF)
        p[len++].id = j;
    dijkstra();
    print();
    return 0;
}

spfa:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3fffffff
#define N 25
int dis[N],pre[N],first[N],used[N];
int n,top,len = 0,start;
struct res{
    int id,dist;
}p[N];
struct edge{
    int y,w,next;
}e[N*N];
void add(int x,int y,int w){
    e[top].y = y;
    e[top].w = w;
    e[top].next = first[x];
    first[x] = top++;
}
int cmp(struct res a,struct res b){
    return a.dist < b.dist;
}
int relax(int x,int y,int w){
    if(dis[y] > dis[x] + w){
        dis[y] = dis[x] + w;
        pre[y] = x;
        return 1;
    }
    return 0;
}
void spfa(){
    int i,q[N*N],front,rear,now;
    rear = front = -1;
    q[++rear] = start;
    memset(used, 0, sizeof(used));
    used[start] = 1;
    for(i = 1;i<=n;i++)
        dis[i] = INF;
    dis[start] = 0;
    while(front < rear){
        now = q[++front];
        used[now] = 0;
        for(i = first[now];i!=-1;i=e[i].next)
            if(relax(now,e[i].y,e[i].w) && !used[e[i].y]){
                q[++rear] = e[i].y;
                used[e[i].y] = 1;
            }
    }
}
void print_dist(int x){
    while(x){
        printf("\t%d",x);
        x = pre[x];
    }
    putchar('\n');
}
void print(){
    int i;
    for(i = 0;i<len;i++)
        p[i].dist = dis[p[i].id];
    sort(p, p+len, cmp);                //按照需要输出的点得路径排序
    printf("Org\tDest\tTime\tPath\n");
    for(i = 0;i<len;i++){
        printf("%d\t%d\t%d",p[i].id,start,p[i].dist);
        print_dist(p[i].id);
    }
}
int main(){
    int i,j,w;
    scanf("%d",&n);
    memset(first, -1, sizeof(first));
    top = 0;
    for(i = 1;i<=n;i++)
        for(j = 1;j<=n;j++){
            scanf("%d",&w);
            if(w!=-1)
                add(j,i,w);
        }
    scanf("%d",&start);
    while(scanf("%d",&j) !=EOF)
        p[len++].id = j;
    spfa();
    print();
    return 0;
}

Floyd:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3fffffff
#define N 25
int dis[N][N],pre[N][N];
int n,len = 0,start;
struct res{
    int id,dist;
}p[N];
int cmp(struct res a,struct res b){
    return a.dist < b.dist;
}
void floyd(){
    int i,j,k;
    for(i = 1;i<=n;i++)
        for(j = 1;j<=n;j++)
            pre[i][j] = i;
    for(k = 1;k<=n;k++)
        for(i = 1;i<=n;i++)
            for(j = 1;j<=n;j++)
                if(dis[i][k] + dis[k][j] < dis[i][j]){
                    dis[i][j] = dis[i][k]+dis[k][j];
                    pre[i][j] = pre[k][j];//注意写成这样而不是pre[i][j] = k在输出的时候更加方便;如果pre[i][j] = k那么输出需要改变
                }
}
void print_dist(int x,int y){
    if(y!=x)
        print_dist(x, pre[x][y]);
    printf("\t%d",y);
}
void print(){
    int i;
    for(i = 0;i<len;i++)
        p[i].dist = dis[p[i].id][start];
    sort(p, p+len, cmp);                //按照需要输出的点得路径排序
    printf("Org\tDest\tTime\tPath\n");
    for(i = 0;i<len;i++){
        printf("%d\t%d\t%d",p[i].id,start,p[i].dist);
        print_dist(p[i].id,start);
        putchar('\n');
    }
}
int main(){
    int i,j,w;
    scanf("%d",&n);
    for(i = 1;i<=n;i++)
        for(j = 1;j<=n;j++){
            scanf("%d",&w);
            if(w==-1)
                dis[i][j] = INF;
            else
                dis[i][j] = w;
        }
    scanf("%d",&start);
    while(scanf("%d",&j) && j)
        p[len++].id = j;
    floyd();
    print();
    return 0;
}

如果Floyd中路径数组写成pre[i][j] = k,那么输出函数要写成:

void print_dist(int x,int y){
    if(pre[x][y]!=x){
        print_dist(x, pre[x][pre[x][y]]);
        print_dist(pre[x][y],y);
        return ;
    }
    if(y!=x)
        printf("\t%d",x);
    printf("\t%d",y);
}


你可能感兴趣的:(poj 1122 最短路+路径追踪(消防路径))