传送门
//题意就不说了.
//题目要求是一定是从标号1出发, 最后到达标号n, 中间不重复的经过完其他岛. 那么问题就是如何搜索. 中间有14个点, 那么最坏的情况就是14!中情况, 这样肯定是会超时的. 所以我们需要剪枝, 因为我们可以发现中途到达某个点时, 如果此时的深度大于了曾经经过的点的深度或者目标点的深度, 那么直接没有搜索下去的必要.
所以我们需要记忆化搜索.
还有一个问题就是如何用state表示当前已经经过了的点的关系 , 因为必须保证中间的岛都要经历过.
所以我们可以用二进制来表示. 例如 : 111 表示从1岛到2再到3. 101 表示从1岛到3. 所以目标状态就是(1<
const int inf= 0x3f3f3f3f; //只有当inf取这个值时才能直接memset.
int n,endstate;
const int maxn = 20;
int dp[maxn][(1<<16)+5]; //最多的状态.
int a[maxn][maxn]; //存的距离关系.
void dfs(int u,int d,int state) //记忆化搜索.
{
if(u == n){
if(state == endstate ) dp[u][state] = min(dp[u][state] , d);
return ;
}
if(d >= dp[u][state] || d >= dp[n][endstate]) return ; //剪枝
dp[u][state] = d;
int i,j;
for(i=2,j=2;i<n;i++,j<<=1){
if(state & j) continue;
dfs(i,d+a[u][i],state | j);
} //最后一个点需要特殊判断, 因为必须是最后到达第n个点.
//而之前不能到达过最后一个点,所以需要特殊判断.
if(state == endstate ^ 1) dfs(i,d+a[u][i],state | j);
}
void solve()
{
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
Fill(dp,inf); //初始化为最大值.
endstate = ( 1<<n )-1; //把目标状态算出来.
dfs(1,0,1);
printf("%d\n",dp[n][endstate]);
}
}