状态转移方程:
dp[state][land] :在状态 state ,所在岛屿为 land 的情况下已经花去的时间
state 代表目前的状态。以二进制数表示,如第3位二进制位为1就表示第3座岛屿(不含起点岛屿)已被访问过。
land 表示当前所在的岛屿。所以 solve(int state,int land) 的最终状态(需要最终输出的值)永远都是 land=n-1 (在终点岛屿的时候)
从 line:26 可以看到我们的状态转移方程就是求出达到状态 state 并且最后达到的岛屿为 id=land 时所有不同走法所用时间中最短的那一个(其实这道题的状态转移方程并不难想,重点在于状压实现,同样类型的题目可以参看POJ 4126 DNA(可能比这道题难一点)以及百度上可以搜到的各种状压DP题)。
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <algorithm>
5 #include <queue>
6 using namespace std;
7 #define INF 0x3f3f3f3f
8 typedef long long LL;
9
10
11 int vis[20];//标记走过的岛屿
12 int minl[20][1<<17];
13 int m[20][20];//从【i】到[j]路程
14 int n,ans;
15
16 void llss(int now,int con) {//dfs函数
17 if(minl[now][con]>ans)
18 return;//剪枝1
19 if((con|1<<(n-1))==(1<<n)-1) {//?????下一位
20 ans=min(ans,minl[now][con]+m[now][n]);
21 return;
22 }
23 for(int i=2; i<=n-1; i++) {
24 if(!vis[i]) {
25 int state=con|(1<<(i-1));
26 if(now==1) {
27 vis[i]=1;
28 minl[i][state]=m[now][i];
29 llss(i,state);
30 vis[i]=0;
31 } else {
32 if(minl[i][state]>minl[now][con]+m[now][i]) {
33 vis[i]=1;
34 minl[i][state]=minl[now][con]+m[now][i];
35 llss(i,state);
36 vis[i]=0;
37 }
38 }
39 }
40 }
41 }
42
43 int main() {
44 //freopen("input.txt","r",stdin);
45 while(~scanf("%d",&n)) {
46 for(int i=1; i<=n; i++)
47 for(int j=1; j<=n; j++)
48 scanf("%d",&m[i][j]);
49
50 memset(vis,0,sizeof(vis));
51 memset(minl,INF,sizeof(minl));
52 ans=INF;
53 vis[1]=1;
54 llss(1,1);
55 printf("%d
",ans);
56
57 }
58 }