题意:一个人从0送外卖,每次送外卖不超过10个地方,给你两两之间所需时间,求送完外卖回到店里的总时间最小,每个地方可以经历到任意次。
思路:弗洛伊德处理下就好了,然后就是经典tsp了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 12;
const int INF = 0x3f3f3f3f;
int dp[maxn][1<<maxn], dis[maxn][maxn], n;
int main()
{
while(~scanf("%d", &n), n)
{
int x;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
{
scanf("%d", &x);
dis[i][j] = x;
}
for(int k = 0; k <= n; k++) //任意次数就直接弗洛伊德
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]);
memset(dp, INF, sizeof(dp));
dp[0][0] = 0; //能回到原点 0不要标记掉
int tot = (1<<(n+1))-1;
for(int state = 0; state <= tot; state++)
{
for(int i = 0; i <= n; i++) //先枚举中间点
{
if(dp[i][state] != INF) //如果这个状态算过才能算下面的最优
{ //就算最短路经过了其他没标记过的点, 最后每个状态都会经历到,肯定会被更新成最优
for(int k = 0; k <= n; k++)
{
if(state&(1<<k)) continue;
dp[k][state|(1<<k)] = min(dp[k][state|(1<<k)], dp[i][state]+dis[i][k]);
}
}
}
}
// int ans = INF;
// for(int i = 1; i <= n; i++)
// ans = min(ans, dp[i][tot-1]+dis[i][0]);
printf("%d\n", dp[0][tot]);
}
return 0;
}