给你一张图,要求遍历所有点且使得总路径最短(最后要回到起始点0)
1、首先用一遍floyd找到所有2点之间的最短距离。
2、状态压缩dp 【 dp[i][j]表示当前状态为j,终点为i的路径长度 】
1)、用n+1为二进制串表示n+1个地点的经过信息,1为经过,0为未经过 (例如n=6, 经过0,3,5点,状态表示为0101001)
2)、状态转移方程 dp[i][j]=min(dp[i][j],dp[k][去掉i点的状态]+map[k][j])
k表示j状态中经过的任意点
去掉i点的状态可以用j&(~(1<<i))表示
判断某个状态是否经过了i点,可以用 (i>>j)&1表示
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int map[12][12];
int dp[12][1<<12];
void debug(int i,int j)
{
printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
scanf("%d",&map[i][j]);
}
}
for(int k=0;k<=n;k++)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
map[i][j]=min(map[i][k]+map[k][j],map[i][j]);
}
}
}
memset(dp,0x3f,sizeof(dp));
int sums=(1<<(n+1));
for(int i=0;i<=n;i++)
{
dp[i][1<<i]=map[0][i];
// debug(i,1<<i);
}
for(int i=1;i<sums;i++)
{
for(int j=0;j<=n;j++)
{
if((i>>j)&1)
{
for(int k=0;k<=n;k++)
{
if(((i>>k)&1))
{
dp[j][i]=min(dp[j][i],dp[k][i&(~(1<<j))]+map[k][j]);
// debug(j,i);
}
}
}
}
}
printf("%d\n",dp[0][sums-1]);
}
return 0;
}