百练 4124 【状态压缩 + 记忆化搜索】

传送门
//题意就不说了.
//题目要求是一定是从标号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]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值