大致思路:
将地铁线路的抽象问题转化为图上最短路径的具体问题,那么最大的难点如何抽象出来。
1.用结构体存储每个站点的信息:包括编号、名称、所经过的线路;
2.names数组存储每个不通过站点的名字,其下表对应着站点的标号,这样读取数据时,可以利用它保证每个站点不被重复构建;
3.map二维数组存储每个站点间的距离;
基本靠以上数据结构就可以将问题具体化了,然后就转为图上的路径规划问题,利用dfs等算法即可解决。
效果展示(推荐dev进行代码运行):
代码:
纯C版本:
#include <stdio.h> #include <string.h> // 站点信息 typedef struct Station{ char name[30]; // 站点名称 int lines[20]; // 经过的线路 int cnt; // 线路数量 }Station; Station stations[100]; // 站点间收费 double map[100][100]; // 站点数量 int staNum; // 站点名称 char names[100][30]; // 标记是否访问过 int visit[100]; // 可选路线数量: int ansNum; // 最优路线: int minLu[100]; // 最优路线中站数量: int minCnt; // 最优价格: double minPrict; // 当前线路: int nowLu[100]; // 查找路线: void dfs(int id1, int id2, int ct, double cost){ int i, j; if(id1 == id2){ printf("可选路线%d: ", ++ansNum); for(i = 0; i < ct; i++){ if(i == 0) printf("%s", names[nowLu[i]]); else printf(" -> %s", names[nowLu[i]]); printf("("); for(j = 0; j < stations[nowLu[i]].cnt; j++){ printf("%d,", stations[nowLu[i]].lines[j]); } printf(")"); } printf(" [费用:%lf] ", cost); // 是否最优: if(cost < minPrict){ minCnt = ct; minPrict = cost; for(i = 0; i < ct; i++){ minLu[i] = nowLu[i]; } } } for(i = 0; i < staNum; i++){ // printf("%d %d %lf %d ", id1, id2, map[id1][i], 0x3f3f3f3f, visit[i]); if(i != id1 && map[id1][i] < 0x3f3f3f3f && visit[i] == 0){ visit[i] = 1; nowLu[ct] = i; // printf("%d %d %d %d %d ",id1, id2, i, ct, nowLu[ct]); dfs(i, id2, ct + 1, cost + map[id1][i]); visit[i] = 0; } } } int main() { // 读入文件:包含线路信息 FILE *fp; int i, j; int id2; fp = fopen("data.txt","r"); //需要创建a.txt文件,然后写入两个数据,空格隔开 // memset(map, 0x3f3f3f3f, sizeof(map)); for (i = 0; i < 100; i++){ for(j = 0; j < 100; j++){ map[i][j] = 0x3f3f3f3f; } } // 站点数量 staNum = 0; for(i = 1; i <= 5; i++){ printf("[%d号线] ", i); while(1){ double f=0; char name1[30]; char name2[30]; fscanf( fp, "%s", &name1); // 每条线路结束符规定为# if(name1[0] == '#'){ printf(" ", i); break; } // 查找当前站点是否存在 int id1 = -1; for(j = 0; j < staNum; j++){ if(strcmp(name1, names[j]) == 0){ id1 = j; break; } } // 如果当前站点不存在,则需要创建 if(id1 == -1){ id1 = staNum; strcpy(names[id1], name1); // stations[id1].name = name1; // 存入名字 strcpy(stations[id1].name, name1); stations[id1].lines[0] = i; // 存入线路 stations[id1].cnt = 1; // 所经过的线路 staNum++; } else{ if (stations[id1].lines[stations[id1].cnt-1] != i){ //考虑是否需要把当前所在线路标号(即线路几)存入该站点的lines stations[id1].lines[stations[id1].cnt] = i; // printf("||| i = %d, %s", i, name1); stations[id1].cnt++; } } // 读入数据: fscanf( fp, "%s%lf", &name2, &f); // 查找当前站点是否存在 id2 = -1; for(j = 0; j < staNum; j++){ if(strcmp(name2, names[j]) == 0){ id2 = j; break; } } // 如果当前站点不存在,则需要创建 if(id2 == -1){ id2 = staNum; // names[id2] = name2; strcpy(names[id2], name2); // stations[id2].name = name2; // 存入名字 strcpy(stations[id2].name, name2); stations[id2].lines[0] = i; // 存入线路 stations[id2].cnt = 1; // 所经过的线路 staNum++; } else{ if(stations[id2].lines[stations[id2].cnt-1] != i){ stations[id2].lines[stations[id2].cnt] = i; // printf("[ i = %d, %d %s] ", i, stations[id2].cnt, name2); stations[id2].cnt++; } } // 加入权重: map[id1][id2] = map[id2][id1] = f; printf("%s->%s %lf ", name1, name2, f); } printf(" "); } // for(int i = 0; i < staNum; i++){ // printf("%s ", stations[i].name); // for(int j = 0; j < stations[i].cnt; j++){ // printf("%d,", stations[i].lines[j]); // } // printf(" "); // } // printf(" "); // 打印矩阵: // for (int i = 0; i < staNum; i++){ // for(int j = 0; j < staNum; j++){ // printf("%lf ", map[i][j]); // } // printf(" "); // } fclose(fp); // 功能启动: while(1){ // 输入需要查找的线路: char n1[30]; char n2[30]; int i, j; // 查找当前站点是否存在 int id1 = -1, id2 = -1; printf("请输入起始点和终点: "); scanf("%s %s", n1, n2); for(j = 0; j < staNum; j++){ if(strcmp(n1, names[j]) == 0){ id1 = j; } // else{ // printf("%s %s ", n1, names[j]); // } if(strcmp(n2, names[j]) == 0){ id2 = j; } } // printf("id1 %s id2 %s ", n1, n2); // printf("您查找的起始点和终点分别是: %s -> %s ", n1, n2); if(id1 == -1 || id2 == -1){ printf("您输入的名称不存在! "); continue; } printf("您查找的起始点和终点分别是: %s -> %s ", n1, n2); // 清空数组 memset(visit, 0, sizeof(visit)); // 可选路线数量 ansNum = 0; nowLu[0] = id1; // 放入起点 visit[id1] = 1; minPrict = 0x3f3f3f3f; // 初始化最优价格 dfs(id1, id2, 1, 0); // 起点, 终点, 路线中数据点个数, 价格 for(i = 0; i < minCnt; i++){ if(i == 0) printf("最优路线:%s", names[minLu[i]]); else printf(" -> %s", names[minLu[i]]); printf("("); for(j = 0; j < stations[minLu[i]].cnt; j++){ printf("%d,", stations[minLu[i]].lines[j]); } printf(")"); } printf(" [费用:%lf] ", minPrict); printf("本次查找结束!!! "); } return 0; }
C++版:
#include <stdio.h> #include <string.h> // 站点信息 typedef struct Station{ char name[30]; // 站点名称 int lines[20]; // 经过的线路 int cnt; // 线路数量 }Station; Station stations[100]; // 站点间收费 double map[100][100]; // 站点数量 int staNum; // 站点名称 char names[100][30]; // 标记是否访问过 int visit[100]; // 可选路线数量: int ansNum; // 最优路线: int minLu[100]; // 最优路线中站数量: int minCnt; // 最优价格: double minPrict; // 当前线路: int nowLu[100]; // 查找路线: void dfs(int id1, int id2, int ct, double cost){ if(id1 == id2){ printf("可选路线%d: ", ++ansNum); for(int i = 0; i < ct; i++){ if(i == 0) printf("%s", names[nowLu[i]]); else printf(" -> %s", names[nowLu[i]]); printf("("); for(int j = 0; j < stations[nowLu[i]].cnt; j++){ printf("%d,", stations[nowLu[i]].lines[j]); } printf(")"); } printf(" [费用:%lf] ", cost); // 是否最优: if(cost < minPrict){ minCnt = ct; minPrict = cost; for(int i = 0; i < ct; i++){ minLu[i] = nowLu[i]; } } } for(int i = 0; i < staNum; i++){ // printf("%d %d %lf %d ", id1, id2, map[id1][i], 0x3f3f3f3f, visit[i]); if(i != id1 && map[id1][i] < 0x3f3f3f3f && visit[i] == 0){ visit[i] = 1; nowLu[ct] = i; // printf("%d %d %d %d %d ",id1, id2, i, ct, nowLu[ct]); dfs(i, id2, ct + 1, cost + map[id1][i]); visit[i] = 0; } } } int main() { // 读入文件:包含线路信息 FILE *fp; fp = fopen("data.txt","r"); //需要创建a.txt文件,然后写入两个数据,空格隔开 // memset(map, 0x3f3f3f3f, sizeof(map)); for (int i = 0; i < 100; i++){ for(int j = 0; j < 100; j++){ map[i][j] = 0x3f3f3f3f; } } // 站点数量 staNum = 0; for(int i = 1; i <= 5; i++){ printf("[%d号线] ", i); while(1){ double f=0; char name1[30]; char name2[30]; fscanf( fp, "%s", &name1); // 每条线路结束符规定为# if(name1[0] == '#'){ printf(" ", i); break; } // 查找当前站点是否存在 int id1 = -1; for(int j = 0; j < staNum; j++){ if(strcmp(name1, names[j]) == 0){ id1 = j; break; } } // 如果当前站点不存在,则需要创建 if(id1 == -1){ id1 = staNum; strcpy(names[id1], name1); // stations[id1].name = name1; // 存入名字 strcpy(stations[id1].name, name1); stations[id1].lines[0] = i; // 存入线路 stations[id1].cnt = 1; // 所经过的线路 staNum++; } else{ if (stations[id1].lines[stations[id1].cnt-1] != i){ stations[id1].lines[stations[id1].cnt] = i; // printf("||| i = %d, %s", i, name1); stations[id1].cnt++; } } // 读入数据: fscanf( fp, "%s%lf", &name2, &f); // 查找当前站点是否存在 int id2 = -1; for(int j = 0; j < staNum; j++){ if(strcmp(name2, names[j]) == 0){ id2 = j; break; } } // 如果当前站点不存在,则需要创建 if(id2 == -1){ id2 = staNum; // names[id2] = name2; strcpy(names[id2], name2); // stations[id2].name = name2; // 存入名字 strcpy(stations[id2].name, name2); stations[id2].lines[0] = i; // 存入线路 stations[id2].cnt = 1; // 所经过的线路 staNum++; } else{ if(stations[id2].lines[stations[id2].cnt-1] != i){ stations[id2].lines[stations[id2].cnt] = i; // printf("[ i = %d, %d %s] ", i, stations[id2].cnt, name2); stations[id2].cnt++; } } // 加入权重: map[id1][id2] = map[id2][id1] = f; printf("%s->%s %lf ", name1, name2, f); } printf(" "); } // for(int i = 0; i < staNum; i++){ // printf("%s ", stations[i].name); // for(int j = 0; j < stations[i].cnt; j++){ // printf("%d,", stations[i].lines[j]); // } // printf(" "); // } // printf(" "); // 打印矩阵: // for (int i = 0; i < staNum; i++){ // for(int j = 0; j < staNum; j++){ // printf("%lf ", map[i][j]); // } // printf(" "); // } fclose(fp); // 功能启动: while(1){ // 输入需要查找的线路: char n1[30]; char n2[30]; printf("请输入起始点和终点: "); scanf("%s %s", n1, n2); // 查找当前站点是否存在 int id1 = -1, id2 = -1; for(int j = 0; j < staNum; j++){ if(strcmp(n1, names[j]) == 0){ id1 = j; } // else{ // printf("%s %s ", n1, names[j]); // } if(strcmp(n2, names[j]) == 0){ id2 = j; } } // printf("id1 %s id2 %s ", n1, n2); // printf("您查找的起始点和终点分别是: %s -> %s ", n1, n2); if(id1 == -1 or id2 == -1){ printf("您输入的名称不存在! "); continue; } printf("您查找的起始点和终点分别是: %s -> %s ", n1, n2); // 清空数组 memset(visit, 0, sizeof(visit)); // 可选路线数量 ansNum = 0; nowLu[0] = id1; // 放入起点 visit[id1] = 1; minPrict = 0x3f3f3f3f; // 初始化最优价格 dfs(id1, id2, 1, 0); // 起点, 终点, 路线中数据点个数, 价格 for(int i = 0; i < minCnt; i++){ if(i == 0) printf("最优路线:%s", names[minLu[i]]); else printf(" -> %s", names[minLu[i]]); printf("("); for(int j = 0; j < stations[minLu[i]].cnt; j++){ printf("%d,", stations[minLu[i]].lines[j]); } printf(")"); } printf(" [费用:%lf] ", minPrict); printf("本次查找结束!!! "); } return 0; }
数据:
a b 4 b c 10 c d 7 d e 4 # f g 3 g c 8 c h 4 h i 1 i j 7 # k l 4 l m 7 m d 3 d n 2 n o 1 # p l 2 l q 1 q r 3 r s 5 s t 9 # u t 1 t v 9 v d 3 d w 7 w x 3 x y 2 #