今天来看看这个算法,鸣谢一位同事给讲解这个算法,算法的思想大家可以去了解一下;
算法主要思想:找出图中任意一点出发,找出到其他点的最短路径;
实现上往往会有一个集合来存放已知点,每次加入一个点;加入的方法是:找出集合点的所有路径,筛选出离A点最近的点,加到集合中。
这里简单的对其实现:
#include <stdio.h>
#include <stdlib.h>
#define N 5 //5个点
typedef enum {
OK,
ERR_OPEN,
ERR_DATA_INPUT
} ERR_NO;
typedef struct cell {
int value;
char is_path_used;
} CELL;
typedef struct map {
char index[N]; //not used..
CELL a[N][N];
}MAP;
static MAP map;
typedef enum{
STATION_A,
STATION_B,
STATION_C,
STATION_D,
STATION_E
}STATION;
typedef struct {
int count;
int value;
STATION a[N];
}NEAREST_PATH;
//已知路径集合
struct s{
int count;
STATION know_set[N];
}know_station_set;
//对应图中的 弧 <v1,v2>
typedef struct v {
int v1_2_v2_value;
int A_2_v2_value;
STATION v1;
STATION v2;
}V_STATION;
//最小路径: Path_A_2_X[0] 表示 A->A
//Path_A_2_X[1] 表示 A->B
//etc.
static NEAREST_PATH Path_A_2_X[5];
int read_data_from_file(void)
{
int i, j;
FILE *fp;
printf("*****************\n");
if((fp = fopen("test.txt", "rt")) == NULL)
{
printf("cannot open file\n");
return -1;
}
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
fscanf(fp, "%d", &map.a[i][j].value);
}
}
printf("read data as:\n");
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
printf("%5d",map.a[i][j].value);
}
printf("\n");
}
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
if(map.a[i][j].value != map.a[j][i].value) return -ERR_DATA_INPUT;
}
}
return 0;
}
char * get_station_name(STATION x)
{
switch(x)
{
case STATION_A: return "A";
case STATION_B: return "B";
case STATION_C: return "C";
case STATION_D: return "D";
case STATION_E: return "E";
default : return "No name";
}
}
int is_station_in_knowset(STATION x)
{
int i;
for(i = 0; i < know_station_set.count; i++)
{
if(x == know_station_set.know_set[i]) return 1;
}
return 0;
}
STATION nearest_station(STATION x)
{
int j;
int min_value = 100, min_num = 0;
for(j = 0; j < N; j++)
{
//printf("j = %d, map.a[%d][%d].value = %d\n", j, x, j, map.a[(int)x][j].value);
//走过的点路径要滤掉
if(map.a[(int)x][j].value != 0 && min_value > map.a[(int)x][j].value
&& !map.a[x][j].is_path_used)
{
//printf("****min_num = %d\n", j);
//集合中已有的点也要滤掉
if(is_station_in_knowset(j)) continue;
min_num = j;
min_value = map.a[(int)x][j].value;
}
//printf("*\n");
}
//printf("min_num = %5d\n", min_num);
printf("%s station's nearest station is: %s\n", get_station_name(x), get_station_name((STATION)min_num));
return (STATION)min_num;
}
void print_path_use_map(void)
{
int i, j;
printf("used path:\n");
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
printf("%5d", map.a[i][j].is_path_used);
}
printf("\n");
}
}
int A_2_knowset_V1_value(STATION v1)
{
return Path_A_2_X[(int)v1].value;
}
//v1 is pre station, x is station now adding
void add_station_2_knowset(STATION x, STATION v1)
{
int i;
know_station_set.know_set[know_station_set.count] = x;
know_station_set.count += 1;
printf("adding station %s\n pre station is %s\n",
get_station_name(x), get_station_name(v1));
printf("the know station set are:\n");
for(i = 0; i < know_station_set.count; i++)
{
printf(" %s ", get_station_name(know_station_set.know_set[i]));
}
printf("\n");
if(v1 == STATION_A)
{
//printf("A->%s\n", get_station_name(x));
Path_A_2_X[x].count = 2;
Path_A_2_X[x].value = map.a[0][x].value;
Path_A_2_X[x].a[1] = x;
}
else
{
printf("copy path: %d to %d\n", v1, x);
//上一个点的最小路径是一样的
memcpy(&Path_A_2_X[x],&Path_A_2_X[v1],sizeof(NEAREST_PATH));
Path_A_2_X[x].a[Path_A_2_X[x].count] = x;
Path_A_2_X[x].count += 1;
Path_A_2_X[x].value += map.a[v1][x].value;
}
}
void pick_station(void)
{
int i, j;
STATION n;
STATION min_2_A;
int min_value = 100;
int min_pre_station = 0;
int break_flag = 0;
V_STATION a[5] = {0};
print_path_use_map();
for(i = 0; i < know_station_set.count; i++)
{
a[i].v1 = know_station_set.know_set[i];
n = nearest_station(a[i].v1); //找已知集合里每个点 最近的点,底下还要进行一次比较
//if(n == -1) continue;
a[i].v2 = n;
//printf("%s", get_station_name(n));
for(j = 0; j < know_station_set.count; j++)
{
if(n == know_station_set.know_set[j])
{
break_flag = 1;
break;
}
}
if(break_flag == 1)
{
break_flag = 0;
continue;
}
//从A出发到备选点的最近距离
a[i].v1_2_v2_value = map.a[a[i].v1][a[i].v2].value;
a[i].A_2_v2_value = A_2_knowset_V1_value(a[i].v1) + a[i].v1_2_v2_value;
//找出距离最小的点
if(a[i].A_2_v2_value < min_value)
{
min_2_A = n;
min_value = a[i].A_2_v2_value;
min_pre_station = a[i].v1;
}
}
//把最小的点添加到已知点集合中
add_station_2_knowset(min_2_A, min_pre_station);
//标记已知集合点所使用的路径,用于滤除备选点
map.a[a[i].v1][min_2_A].is_path_used = 1;
map.a[min_2_A][a[i].v1].is_path_used = 1;
}
void init_find_path(void)
{
int i;
know_station_set.know_set[know_station_set.count] = STATION_A;
know_station_set.count += 1;
Path_A_2_X[0].count = 1;
Path_A_2_X[0].value = 0;
Path_A_2_X[0].a[0] = STATION_A;
}
void print_near_path(void)
{
int i, j;
printf("\n*****print result******\n");
for(i = 0; i < N; i++)
{
printf("A->%s path is:\n", get_station_name(i));
for(j = 0; j < Path_A_2_X[i].count; j++)
{
printf(" %s ", get_station_name(Path_A_2_X[i].a[j]));
}
printf("\n the cost is: %d\n", Path_A_2_X[i].value);
printf("---\n");
}
}
int main(int argc, char *argv[])
{
int res;
res = read_data_from_file();
if(res == -ERR_DATA_INPUT)
{
printf("err data input\n");
system("PAUSE");
return;
}
init_find_path();
pick_station();
pick_station();
pick_station();
pick_station();
print_near_path();
system("PAUSE");
return 0;
}