题意:一个人送外卖,每次送外卖不超过10个地方,给你两两之间所需时间,求送完外卖回到店里的总时间最小。
思路:先floyd跑一下两两之间最短路; dp[i][j]表示i状态时并且现在处于j位置时所用的最少时间。
状态转移方程:dp[i][v] = min(dp[i][v], dp[i^(1<<(v-1))][u]+a[u][v])
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 12;
const int INF = 0x3f3f3f3f;
int a[maxn][maxn], n;
int dp[1<<maxn][maxn];
int main(void)
{
while(cin >> n, n)
{
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
scanf("%d", &a[i][j]);
for(int k = 0; k <= n; k++)
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
a[i][j] = min(a[i][j], a[i][k]+a[k][j]);
memset(dp, INF, sizeof(dp));
int tot = (1<<n)-1;
for(int i = 0; i <= tot; i++)
{
for(int v = 1; v <= n; v++)
{
if(i&(1<<(v-1)))
{
if(i == 1<<(v-1))
dp[i][v] = a[0][v];
else
{
dp[i][v] = INF;
for(int u = 1; u <= n; u++)
{
if(u != v && (i&(1<<(u-1))))
{
dp[i][v] = min(dp[i][v], dp[i^(1<<(v-1))][u]+a[u][v]);
}
}
}
}
}
}
int ans = INF;
for(int i = 1; i <= n; i++)
ans = min(ans, dp[tot][i]+a[i][0]);
printf("%d\n", ans);
}
return 0;
}