题目连接:http://poj.org/problem?id=3311
题意:一个送披萨的,每次送外卖不超过10个地方,给你这些地方之间的时间,求送完外卖回到店里的总时间最小。
分析:跑一遍Floyd求出两两之间的最短距离,然后就是一个裸TSP问题了。
dp[state][i]表示在state状态下(state的二进制1表示经过的点)当前处于i点的的最少时间。
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-9
#define N 100010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int dis[][],n;
int dp[][];
void floyd()
{
for(int k=;k<=n;k++)
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j];
}
int main()
{
while(scanf("%d",&n)&&n)
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
scanf("%d",&dis[i][j]);
floyd();
for(int s=;s<(<<n);s++)
for(int i=;i<=n;i++)
{
if(s&(<<(i-)))//经过i点
{
if(s==(<<(i-)))dp[s][i]=dis[][i];
else
{
dp[s][i]=inf;
for(int j=;j<=n;j++)
{
if((s&(<<(j-)))&&i!=j)//经过j点
dp[s][i]=min(dp[s][i],dp[s^(<<(i-))][j]+dis[j][i]);//松弛
}
}
}
}
int ans=inf;
for(int i=;i<=n;i++)
if(dp[(<<n)-][i]+dis[i][]<ans)
ans=dp[(<<n)-][i]+dis[i][];
printf("%d\n",ans);
}
}