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