城市距离问题
问题描述:
用无序表实现一个城市数据库。每条数据库记录包括城市名(任意长的字符串)和城市的坐标(用整数x和y表示)。实现数据的插入、删除、查询功能,并实现指定距离内的所有城市。设计算法实现指定一定数目的具体城市,寻找遍历这些城市并回到出发点的最佳路径,观察随着城市数目的增加,算法执行效率的变化。
编程任务:
① 用列表对城市进行记录和管理,实现城市的增加、删除和查询功能,并实现文件保存和读取
② 计算城市之间距离,统计输出距离某城市一定范围内的所有城市。
③ 实现一定规模城市的遍历最佳路径选择。
④ 分析随着城市数目增加时,算法执行效果的改变,深刻理解旅行商问题。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define maxlen 100
typedef struct list
{
char name[maxlen]; //城市名
int x; //横坐标
int y; //纵坐标
}list;
typedef struct Sum
{
double sum;//两个城市之间的距离
char sumnamea[20];//第一个城市
char sumnameb[20];//第二个城市
}Sum;
typedef struct Point
{
char pointname[20];
int point;
}point;
void readcity(int strline[100][2],char str[100][20]);
void putmassintofile(list city)//将城市信息输入文件中
{
FILE *p;
int strline[100][2];
char str[100][20];
int i,j;
p = fopen("City Massage.txt","a");
if(p==NULL)
{
printf("文件打开失败。\n");
system("pause");
return;
}
readcity(strline,str);
for(i=0;i<100;i++)
{
if(city.x==strline[i][0] && city.y==strline[i][1])
{
if(strcmp(city.name,str[i])==0)
{
printf("输入完成\n\n");
break;
}
else
{
printf("输入错误,已经有另一座城市。\n\n");
break;
}
}
else if(strcmp(city.name,str[i])==0)
{
if(city.x==strline[i][0] && city.y==strline[i][1])
{
printf("输入完成\n\n");
break;
}
else
{
printf("输入错误,该城市在另一处。\n\n");
break;
}
}
else
{
fprintf(p,"%s\t",city.name);
fprintf(p,"%d\t",city.x);
fprintf(p,"%d\n",city.y);
printf("输入完成\n\n");
break;
}
}
fclose(p);
}
void readcity(int strline[100][2],char str[100][20])//寻找城市:读取文件
{
FILE *p;
int i=0;
p = fopen("City Massage.txt","r");
if(p==NULL)
{
printf("文件打开失败。\n");
system("pause");
return;
}
while(fscanf(p,"%s %d %d\n",&str[i],&strline[i][0],&strline[i][1])!=EOF)
{
i++;
}
str[i][0] = '*';
fclose(p);
}
void findcity(int strline[100][2],char str[100][20])//寻找城市
{
int m,x,y;
int i;
char *s;
printf("选择查找方式。\n");
printf("1.城市名\n2.横纵坐标\n\n");
scanf("%d",&m);
switch(m)
{
case 1:
{
printf("输入城市名\n");
scanf("%s",s);
for(i=0;i<100;i++)
{
if(strcmp(s,str[i])==0)
{
printf("查找成功\n");
printf("%s\t%d\t%d\n\n",str[i],strline[i][0],strline[i][1]);
break;
}
}
break;
}
case 2:
{
printf("输入横纵坐标\n");
scanf("%d %d",&x,&y);
for(i=0;i<100;i++)
{
if(x==strline[i][0] && y==strline[i][1])
{
printf("查找成功\n");
printf("%s\t%d\t%d\n\n",str[i],strline[i][0],strline[i][1]);
break;
}
}
break;
}
default:
{
printf("输入错误\n");
}
}
}
void deletecity(char *s)//删除城市
{
int strline[100][2];
int i,j;
char str[100][20];
FILE *p;
readcity(strline,str);
p = fopen("City Massage.txt","w+");
if(p==NULL)
{
printf("文件打开失败。\n");
system("pause");
return;
}
for(i=0;i<100;i++)
{
j = i+1;
if(strcmp(str[i],s)!=0)
{
fprintf(p,"%s\t",str[i]);
fprintf(p,"%d\t",strline[i][0]);
fprintf(p,"%d\n",strline[i][1]);
if(str[j][0]=='*')
{
break;
}
}
}
fclose(p);
}
void getthefastway(void);
void countcity(char *s,int m);
int main(void)
{
list c;
int strline[100][2],m;
char str[100][20];
char as[20];
int i;
loop:
printf("1.输入城市信息\n2.查找城市\n3.删除城市\n");
printf("4.列出所有城市\n");
printf("5.输出距离某城市一定范围内的所有城市。\n");
printf("6.从某一城市出发,遍历所有城市,并返回起点的最佳路径。\n");
printf("7.退出。\n\n");
scanf("%d",&m);
switch(m)
{
case 1:
{
printf("输入城市名、横坐标、纵坐标。\n");
scanf("%s %d %d",c.name,&c.x,&c.y);
putmassintofile(c);
goto loop;
}
case 2:
{
readcity(strline,str);
findcity(strline,str);
goto loop;
}
case 3:
{
printf("输入城市名。\n");
scanf("%s",as);
deletecity(as);
goto loop;
}
case 4:
{
readcity(strline,str);
for(i=0;i<100;i++)
{
if(str[i][0]!='*')
{
printf("%s\t%d\t%d\n",str[i],strline[i][0],strline[i][1]);
}
else
{
break;
}
}
printf("\n");
goto loop;
}
case 5:
{
printf("输入特定的城市和范围的大小。\n");
scanf("%s %d",as,&m);
countcity(as,m);
goto loop;
}
case 6:
{
getthefastway();
goto loop;
}
case 7:
{
goto ssr;
}
default :
{
printf("输入错误");
system("pause");
goto loop;
}
}
ssr:
return 0;
}
void countcity(char *s,int m)//计算特定城市到其他城市的距离,输出距离该城市一定范围内的所有城市
{
int strline[100][2];
char str[100][20];
int x,y;
int i,j;
Sum sumall[maxlen];//记录所有的距离信息
readcity(strline,str);
for(i=0;i<100;i++)
{
sumall[i].sum = 0;
}
for(i=0;i<100;i++)
{
if(str[i][0]!='*')
{
if(strcmp(str[i],s)==0)
{
x = strline[i][0];
y = strline[i][1];
break;
}
}
else
{
printf("该城市不在列表中。\n");
break;
}
}
j = 0;
for(i=0;i<100;i++)
{
if(str[i][0]!='*')
{
if(strcmp(str[i],s)!=0)
{
sumall[j].sum = sqrt((x-strline[i][0])*(x-strline[i][0])+(x-strline[i][1])*(x-strline[i][1]));
strcpy(sumall[j].sumnamea,str[i]);
strcpy(sumall[j].sumnameb,s);
j = j+1;
}
}
else
{
break;
}
}
for(i=0;i<100;i++)
{
if(sumall[i].sum!=0)
{
if(sumall[i].sum<=m)
{
printf("%s\t%f\n",sumall[i].sumnamea,sumall[i].sum);
}
}
else
{
break;
}
}
printf("\n");
}
double countlong(char str[20],Sum waylong[10000],point all[maxlen],char thewholeway[100][20]);
void getthefastway(void)//得到最佳遍历选择
{
int strline[100][2];
char str[100][20];//读取文件用
int i,j,k;
point all[maxlen];//记录每一个点
Sum waylong[10000];//每一条路的长度
int x1,x2,y1,y2;
double sumlong[100];//总长度
double m;//记录最短距离
char thewholeway[100][20];//记录每一条路线
char really[100][20];//选出最短路线
readcity(strline,str);
for(i=0;i<100;i++)//所有的点都未去过
{
all[i].point = 0;
sumlong[i] = 0;
}
for(i=0;i<10000;i++)//重置所有距离
{
waylong[i].sum = 0;
}
for(i=0;i<100;i++)//赋予所有点名字
{
if(str[i][0]!='*')
{
strcpy(all[i].pointname,str[i]);
}
else
{
break;
}
}
all[i].pointname[0] = '*';//判断点的个数
k = 0;
for(i=0;i<100;i++)//计算所有的距离
{
if(str[i][0]!='*')
{
x1 = strline[i][0];
y1 = strline[i][1];
for(j=i+1;j<100;j++)
{
if(str[j][0]!='*')
{
x2 = strline[j][0];
y2 = strline[j][1];
waylong[k].sum = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
strcpy(waylong[k].sumnamea,str[i]);
strcpy(waylong[k].sumnameb,str[j]);
k = k+1;
}
else
{
break;
}
}
}
else
{
break;
}
}
for(i=0;i<10000;i++)//从小到大依次排序,选出距离最短的
{
if(waylong[i].sum!=0)
{
for(j=i+1;j<10000;j++)
{
if(waylong[j].sum!=0)
{
if(waylong[i].sum>waylong[j].sum)
{
k = waylong[i].sum;
waylong[i].sum = waylong[j].sum;
waylong[j].sum = k;
}
}
else
{
break;
}
}
}
else
{
break;
}
}
for(i=0;i<100;i++)
{
if(all[i].pointname[0]!='*')
{
sumlong[i] = countlong(all[i].pointname,waylong,all,thewholeway);
//printf("%s\t%f\n",all[i].pointname,sumlong[i]);//输出每一条路径的起点和总长度
if(i==0)//第一次,直接赋予
{
m = sumlong[0];
j = 0;
for(k=0;k<100;k++)
{
if(thewholeway[k][0]!='*')
{
strcpy(really[k],thewholeway[k]);
}
else
{
break;
}
}
really[k][0]='*';
}
else if(m>sumlong[i])//比较,选出最小
{
m = sumlong[i];
j = i;//判断起点
for(k=0;k<100;k++)
{
if(thewholeway[k][0]!='*')
{
strcpy(really[k],thewholeway[k]);
}
else
{
break;
}
}
really[k][0]='*';
}
}
else
{
break;
}
}
printf("\n最短的遍历路径:\n");
for(i=0;i<100;i++)
{
if(really[i][0]!='*')
{
printf("%s",really[i]);
j = i+1;
if(really[j][0]!='*')
{
printf("-->");
}
}
else
{
break;
}
}
printf("\n最短距离:\n%f\n\n",m);
}
double countlong(char str[20],Sum waylong[10000],point all[maxlen],char thewholeway[100][20])//计算从某个城市出发的最短路径,并返回总值
{
int i,j,k;
double sum=0;
char s1[20],s2[20];
char strx[20];
for(i=0;i<100;i++)
{
if(all[i].pointname[0]!='*')
{
all[i].point = 0;
}
else
{
break;
}
}
for(j=0;j<100;j++)//起点已去过
{
if(strcmp(str,all[j].pointname)==0)
{
all[j].point = 1;
break;
}
}
k = 0;
strcpy(thewholeway[k],str);
strcpy(strx,str);//将strx作为起点
for(i=0;i<10000;i++)//从最短距离开始
{
if(waylong[i].sum==0)
{
break;
}
strcpy(s1,waylong[i].sumnamea);
strcpy(s2,waylong[i].sumnameb);
if(strcmp(strx,s1)==0)//如果起点strx与s1符合
{
for(j=0;j<100;j++)
{
if(strcmp(s2,all[j].pointname)==0)//找到最短距离且未访问过
{
if(all[j].point==0)
{
all[j].point = 1;//访问节点
sum = waylong[i].sum+sum;
strcpy(strx,s2);//以s2为新节点
k = k+1;
strcpy(thewholeway[k],strx);
i = -1;//从头开始
break;
}
else
{
break;
}
}
else if(all[j].pointname[0]=='*')
{
break;
}
}
}
else if(strcmp(strx,s2)==0)//起点strx与s2符合
{
for(j=0;j<100;j++)
{
if(strcmp(s1,all[j].pointname)==0)
{
if(all[j].point==0)
{
all[j].point = 1;
sum = waylong[i].sum+sum;
strcpy(strx,s1);
k = k+1;
strcpy(thewholeway[k],strx);
i = -1;
break;
}
else
{
break;
}
}
else if(all[j].pointname[0]=='*')
{
break;
}
}
}
}
k = k+1;
strcpy(thewholeway[k],str);
k = k+1;
thewholeway[k][0] = '*';//路程记录完毕,截止
for(i=0;i<10000;i++)//回到原点
{
if(strcmp(strx,waylong[i].sumnamea)==0 && strcmp(str,waylong[i].sumnameb)==0)
{
sum = waylong[i].sum+sum;
break;
}
else if(strcmp(str,waylong[i].sumnamea)==0 && strcmp(strx,waylong[i].sumnameb)==0)
{
sum = waylong[i].sum+sum;
break;
}
}
return sum;
}