题意:给你一个有n+1(1<=n<=10)个点的有向完全图,用矩阵的形式给出任意两个不同点之间的距离。(其中从i到j的距离不一定等于从j到i的距离)现在要你求出从0号点出发,走过1到n号点至少一次,然后再回到0号点所花的最小时间。
输入:包含多组实例。每个实例第一个为n,然后是n+1行矩阵,每行矩阵有n+1个数字,第i行第j个数字表示从i-1到j-1号点的距离。当输入n=0时表示输入结束。
输出:最小距离。
这题有两种思路:一种是网上普遍的做法就是先求一遍floyd,求出各个点之间的最短路,然后就转化为了TSP问题去求解。需要注意的就是初始化的问题。
附上代码:
#include<iostream>
#define INF 100000000
using namespace std;
int dis[12][12];
int dp[1<<11][12];
int n,ans,_min;
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n) && n)
{
for(int i = 0;i <= n;++i)
for(int j = 0;j <= n;++j)
scanf("%d",&dis[i][j]);
for(int k = 0;k <= n;++k)
for(int i = 0;i <= n;++i)
for(int j = 0;j <=n;++j)
if(dis[i][k] + dis[k][j]< dis[i][j])
dis[i][j] = dis[i][k] +dis[k][j];
for(int S = 0;S <= (1<<n)-1;++S)//枚举所有状态,用位运算表示
for(int i = 1;i <= n;++i)
{
if(S & (1<<(i-1)))//状态S中已经过城市i
{
if(S ==(1<<(i-1))) dp[S][i] =dis[0][i];//状态S只经过城市I,最优解自然是从0出发到i的dis,这也是DP的边界
else//如果S有经过多个城市
{
dp[S][i] = INF;
for(int j = 1;j <=n;++j)
{
if(S &(1<<(j-1)) && j != i)//枚举不是城市I的其他城市
dp[S][i] =min(dp[S^(1<<(i-1))][j] + dis[j][i],dp[S][i]);
//在没经过城市I的状态中,寻找合适的中间点J使得距离更短
}
}
}
}
ans = dp[(1<<n)-1][1] + dis[1][0];
for(int i = 2;i <= n;++i)
if(dp[(1<<n)-1][i] + dis[i][0] < ans)
ans = dp[(1<<n)-1][i] +dis[i][0];
printf("%d\n",ans);
}
return 0;
}
下面主要讲讲我的做法。我们可以从题目中发现这题与典型的TSP最大区别就是这题的顶点是可以经过多次的,而普通的TSP只能经过一次。
所以根据挑战上关于TSP的代码我们可以发现,他在状态转移的时候是加了一个判断的,只有当前节点不在某一状态的时候,才会进行状态转移。那么我们就可以类推,因为顶点经过次数没有限制,所以只需要把判断条件去掉即可。
注意:我下面代码将n++了,就说明数据范围从[0,n]变为了[1,n+1]
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[5000][15];
int n;
int e[15][15];
int main() {
while(~scanf("%d", &n) && n) {
n++;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
int x;
scanf("%d", &x);
e[i][j] = x;
}
}
memset(dp, inf, sizeof(dp));
dp[(1 << n) - 1][1] = 0;
for(int s = (1 << n) - 1; s >= 0; s--) { //每一种状态
for(int i = 1; i <= n; i++) { //当前所在城市
for(int j = 1; j <= n; j++) { //一种状态的每一位,将要去的城市
dp[s][i] = min(dp[s][i], dp[s | 1 << (j - 1)][j] + e[j][i]);
}
}
}
printf("%d\n", dp[1][1]);
}
return 0;
}