Description
题意是有n个城市(1~n)和一个披萨店(0),要求一条回路,从0出发,又回到0,而且距离最短
Input
多组输入,每组用例第一行为一个整数n表示成熟数量,之后为一个(n+1)*(n+1)矩阵表示n个城市和披萨店之间的距离矩阵,以n=0结束输入
Output
对于每组用例,输出最短距离
Sample Input
3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
0
Sample Output
8
Solution
TSP(旅行商)问题,首先不难想到用FLOYD先求出任意2点的距离dis[i][j],接着枚举所有状态,用11位二进制表示10个城市和披萨店,1表示经过,0表示没有经过 定义状态dp[state][j]表示在state状态下,到达城市I的最优值,接着状态转移方程:dp[state][i] = min{dp[s^(1<<(i-1)][k]) + dis[k][i],dp[state][i])},(state^(1<<(i-1))表示未到达城市i的所有状态,1<=k<=n)。对于全1的状态,即state=(1<< n)-1则表示经过所有城市的状态,最终还需要回到披萨店0,那么最终答案就是min{dp[state][i]+dis[i][0]}
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 1<<29
int dp[(1<<11)+5][11];
int main()
{
int n;
while(scanf("%d",&n),n)
{
int dis[11][11];
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
scanf("%d",&dis[i][j]);
//Floyd求最短路
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,0,sizeof(dp));//初始化
for(int state=0;state<(1<<n);state++)//枚举所有状态
for(int i=1;i<=n;i++)//枚举所有城市
if(state&(1<<(i-1)))//去过i城市
{
if(state==(1<<(i-1)))//只去过i城市显然此状态最短路即为披萨店到i城市最短路
dp[state][i]=dis[0][i];
else//还去过其他城市
{
dp[state][i]=INF;//初始化
//从此状态经过的其他城市中选取合适的中间点j城市使得总距离最小
for(int j=1;j<=n;j++)
if(i!=j&&state&(1<<(j-1)))
dp[state][i]=min(dp[state][i],dp[state^(1<<(i-1))][j]+dis[j][i]);//更新最短总距离
}
}
//从经过所有城市的状态中选取最短总距离
int ans=dp[(1<<n)-1][1]+dis[1][0];
for(int i=2;i<=n;i++)
ans=min(ans,dp[(1<<n)-1][i]+dis[i][0]);
printf("%d\n",ans);
}
return 0;
}