思路分析:状态dp[i][j]表示状态为i时以j结尾的最短路径,然后还要返回起点,因此用一个start函数保存该状态下的起点,通过三个for循环
for()//枚举状态
{
for()//枚举终点
{
for()//枚举该状态没有的城市
{
//将最小的dp记录,并保存start
}
}
}
可能会有疑问如果,该状态没有这个城市如何在第二层for循环让他作为终点呢,所以初始化很重要,下面是例题的dp运算过后的值,我们可以发现像dp[001][1]这种不可能的值都是无限大。
详细程序
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include<algorithm>
using namespace std;
#define S 1<<15
const int INF = 0x3f3f3f3f;
int dp[S][15];
int start[S][15];
int map[20][20];
int main()
{
int n;
int i, j, k;
while (~scanf("%d", &n))
{
int end;
int cur,curtemp;
memset(start, 0, sizeof(start));
memset(map, 0, sizeof(map));
memset(dp, 0, sizeof(dp));
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
scanf("%d", &map[i][j]);
}
}
end = (1 << n) - 1;
for (i = 0; i <= end; i++)
{
for (j = 0; j < n; j++)
{
dp[i][j] = INF;
}
}
for (i = 0; i<n; i++)
{
dp[0][i] = 0;
start[0][i] = i;
}
for (i = 0; i<=end; i++)
{
for (j = 0; j<n; j++)
{
for (k = 0; k<n; k++)
{
cur = 1 << k;
if ((i&cur) == 0)
{
curtemp = i | cur;//将访问的城市加入到该状态中
if (dp[i][j] + map[j][k]<dp[curtemp][k])
{
dp[curtemp][k] = dp[i][j] + map[j][k];
start[curtemp][k] = start[i][j];//加入改变终点,起点不改变
}
}
}
}
}
int Min = INF;
for (i = 0; i<n; i++)
{
int Start = start[end][i];
Min =min(Min, dp[end][i] + map[i][Start]);//访问完所有的点+回到起点
}
printf("%d\n", Min);
}
return 0;
}