题意: 该题用到了状态压缩动态规划,时间复杂度是O(2^n)*(n^2),因为n数量较少所以可以用这种方法,
其中需要注意的是前n的二进制数表示是2的n此方减1,
解题思想:dp[i][j] 就是表示j属于i这个集合里的数,表示的是以j为结尾时的最小值,就是遍历以i集合内的数为结尾的值求最小值,
然后再考虑影响当前状态的条件,依次递推
#include<bits/stdc++.h>
using namespace std;
const int maxn=(1<<16)+1;
const int m=16+1;
int dp[maxn][m];
int p[m][m];
int main()
{
int i,j,k,n,_j,_k;
while(scanf("%d",&n)==1)
{
for(i=1; i<=n; ++i)
{
for(j=1; j<=n; ++j)
{
scanf("%d",&p[i][j]);
}
}
memset(dp,0x7f,sizeof(dp));
dp[1][1]=0; //这个先决条件不可以少
int ans=1<<n;
for(i=1; i<ans; ++i) // 当n=2时 ans 二进制数为11当n = 3时 ans = 二进制数111,所以最终输出为dp[ans-1][n]
{
for(j=1,_j=1; j<=n; ++j,_j<<=1)
{
if(i&_j) //岛屿j在去过的岛屿i中
{
for(k=1,_k=1; k<=n; _k<<=1,++k)
{
if(k!=j&&(i&_k))
{
dp[i][j]=min(dp[i][j],dp[i-_j][k]+p[k][j]);
}
}//如k = 7时对应的二进制数为111。dp[7(111)][2] = min(dp[7(111)][2],dp[5(101)][j]+G[j][i])。
//在求dp[7][x]用到了dp[5][x](x无实意),因为是从小到大开始遍历,所以此时dp[5][x]已经求出
}
}
}
printf("%d\n",dp[ans-1][n]);
}
return 0;
}