题意:在一个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; }
#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; }
#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); }