任务描述
输入格式
第一行输入n,代表有n个城市。
接下来n行每行输入n个数,第i行j列的值代表i市到j市的距离,0代表城市之间不通
注意:起点和终点都为1
n<7,城市之间的距离都不超过100
输出格式
第一行输出最少的旅行费用
第二行输入旅行路径
(保证只有一条最短旅行路径)
Sample Input
4
0 30 6 4
30 0 5 10
6 5 0 20
4 10 20 0
Sample Output
25
1 3 2 4 1
#include<stdio.h>
#define MAX 100
int n; //城市个数
int c[MAX][MAX]; //城市间距离
int point[MAX]; //记录点
int bestPath[MAX] = { 0 }; //记录最优路径
int minLen = 63355; //最短路径长
int nowLen = 0; //当前路径长
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
void backpack(int t) {//t = 2,假设从1点开始
if (t > n) {//当t = 5时,说明要找回路了
//如果最后一个点能直接回到起点,且路线最短,存储到bestPath
if ((c[point[n]][1]) && (c[point[n]][1] + nowLen < minLen)) {
minLen = c[point[n]][1] + nowLen;
for(int i = 1; i <= n; i++) bestPath[i] = point[i];
}
}
else {
for (int i = t; i <= n; i++) {
//如果路径存在,并且加入这条路径后总长更短
//如果加入当前路径不会更短,那就会i++, 就会导致i和t不一样,就要交换点,调用swap
if ((c[point[t - 1]][point[i]]) && (nowLen + c[point[t - 1]][point[i]] < minLen)) {
if (i != t) swap(&point[t], &point[i]);
nowLen += c[point[t - 1]][point[t]];//加入这条路线长度
backpack(t + 1);//查看下一个点
//上面是t+1,当走完所有景点,t+1>n,backpack(t+1)if语句走完就要执行下面的语句,也就是回溯
nowLen -= c[point[t - 1]][point[t]];
if (i != t) swap(&point[t], &point[i]);
}
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) point[i] = i;//将各个顶点放入集合
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &c[i][j]);
}
}
backpack(2);//默认先以1为出发点
printf("%d\n", minLen);//输出最短距离
for (int i = 1; i <= n; i++) printf("%d ", bestPath[i]);//输出旅行路线
printf("%d", bestPath[1]);
return 0;
}
可能swap的功能会比较难以理解
下面的代码只是相比上面的代码多了一些向人们展示了代码的运行过程的代码,可以通过观察运行结果加深对代码执行过程的认识
#include<stdio.h>
#define MAX 100
int n; //城市个数
int cnt = 1;
int c[MAX][MAX]; //城市间距离
int point[MAX]; //记录点
int bestPath[MAX] = { 0 }; //记录最优路径
int minLen = 63355; //最短路径长
int nowLen = 0; //当前路径长
void swap(int* a, int* b) {
int t = *a;
*a = *b;
*b = t;
}
void backpack(int t) {//t = 2,假设从1点开始
if (t > n) {//当t = 5时,说明要找回路了
//如果最后一个点能直接回到起点,且路线最短,存储到bestPath
if ((c[point[n]][1]) && (c[point[n]][1] + nowLen < minLen)) {
minLen = c[point[n]][1] + nowLen;
printf("我找到了目前最优路径:");
for(int i = 1; i <= n; i++) {
bestPath[i] = point[i];
printf("%d ", point[i]);
}
printf("\n");
}
}
else {
for (int i = t; i <= n; i++) {
//如果路径存在,并且加入这条路径后总长更短
//如果加入当前路径不会更短,那就会i++, 就会导致i 和 t不一样,就要交换点
//后面走完所有路径且有回路,bestPath会把这些点序存储起来
if ((c[point[t - 1]][point[i]]) && (nowLen + c[point[t - 1]][point[i]] < minLen)) {
if (i != t) {
printf("交换前point[%d] = %d point[%d] = %d\n", i, point[i], t, point[t]);
swap(&point[t], &point[i]);
printf("交换后point[%d] = %d point[%d] = %d\n", i, point[i], t, point[t]);
printf("第%d次点交换:", cnt++);
for (int j = 1; j <= i; j++) {
printf("%d ", point[j]);
}
}
//printf("\n");
nowLen += c[point[t - 1]][point[t]];//加入这条路线长度
printf("加入了一个点%d\n", point[i]);
backpack(t + 1);//查看下一个点
//上面是t+1,当走玩所有景点,t+1>n,backpack(t+1)if语句走完就要执行下面的语句
printf("回溯了\n");
nowLen -= c[point[t - 1]][point[t]];
if (i != t) {
printf("交换前point[%d] = %d point[%d] = %d\n", i, point[i], t, point[t]);
swap(&point[t], &point[i]);
printf("交换后point[%d] = %d point[%d] = %d\n", i, point[i], t, point[t]);
printf("第%d次点交换:", cnt++);
for (int j = 1; j <= i; j++) {
printf("%d ", point[j]);
}
}
printf("\n");
}
}
}
}
/*
4
0 30 6 4
30 0 5 10
6 5 0 20
4 10 20 0
*/
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
point[i] = i;//将各个顶点放入集合
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &c[i][j]);
}
}
backpack(2);//默认先以1为出发点
printf("%d\n", minLen);//输出最短距离
for (int i = 1; i <= n; i++) printf("%d ", bestPath[i]);//输出旅行路线
printf("%d", bestPath[1]);
return 0;
}