动态规划【8】之状态压缩DP

10 篇文章 0 订阅
9 篇文章 0 订阅

状态压缩DP将状态作为数组的一维,进行动态规划。

例题:luogu1433 吃奶酪

房间里放着 n n n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ( 0 , 0 ) (0,0) (0,0) 点处。
输出要跑的最少距离。
其中 n ≤ 15 n \leq 15 n15

因为要把所有的奶酪吃完,所以我们要考虑吃的顺序,不同的顺序对结果有很大的影响。从暴力的角度看,共有 n ! n! n!个顺序,当 n = 15 n=15 n=15时, n ! = 1307674368000 n!=1307674368000 n!=1307674368000,显然会超时。

优化,考虑如下情况:
假设现在已经吃了 3 3 3块奶酪,要去吃剩下的 n − 3 n-3 n3块。已经吃的 3 3 3块中只有最后一块,对剩下的 n − 3 n-3 n3块的按什么顺序吃有影响。如前三块编号为 1 1 1 2 2 2 3 3 3, 那么 123 123 123(先吃第 1 1 1块,再吃第 2 2 2块,最后吃第 3 3 3块), 213 213 213对剩下 n − 3 n-3 n3块按什么顺序吃是没有影响的。也就是说,我们对于已经吃过的奶酪,只关心吃了哪几块,和最后一块吃了哪一块。由此,可以减少状态数。

刚刚介绍的也是状态压缩的基本思想。现在开始介绍状态压缩,设 m a s k mask mask表示 n n n位长度的二进制,第 i i i位(从右往左数, i i i 0 0 0开始)为 1 1 1时表示吃了第 i i i块奶酪,为 0 0 0时表示还没吃第 i i i块奶酪。

n = 7 n=7 n=7, m a s k mask mask在二进制表示下为 0000111 0000111 0000111,表示已经吃了第 0 0 0块,第 1 1 1块,第 2 2 2块奶酪,没有吃第 3 3 3块,第 4 4 4块,第 5 5 5块,第 6 6 6块奶酪;

n = 7 n=7 n=7, m a s k mask mask在二进制表示下为 1000101 1000101 1000101,表示已经吃了第 0 0 0块,第 2 2 2块,第 6 6 6块奶酪,没有吃第 1 1 1块,第 3 3 3块,第 4 4 4块,第 5 5 5块奶酪。

那么DP的状态 d p [ m a s k ] [ i ] dp[mask][i] dp[mask][i]表示在 m a s k mask mask状态,最后一块吃的是 i i i下的最小距离和。

输出吃了所有奶酪,最后一个吃的是 i i i下取一个最小值:
min ⁡ { d p [ ( 1 < < n ) − 1 ] [ i ] } , 0 ≤ i ≤ n − 1 , \min\{dp[(1<<n)-1][i]\}, 0\leq i\leq n-1, min{dp[(1<<n)1][i]},0in1,其中 ( 1 < < n ) − 1 (1<<n)-1 (1<<n)1二进制下的表示 n n n 1 1 1,即吃了所有奶酪。

转移式:
d p [ m a s k ] [ i ] = min ⁡ { d p [ m a s k − ( 1 < < i ) ] [ j ] + d i s ( i , j ) } , dp[mask][i] = \min\{dp[mask-(1<<i)][j]+dis(i,j)\}, dp[mask][i]=min{dp[mask(1<<i)][j]+dis(i,j)},
其中 d i s ( i , j ) dis(i,j) dis(i,j)表示下标为 i i i j j j的距离; m a s k mask mask要包含 i i i j j j两个状态,即 ( m a s k & ( 1 < < i ) ) > 0 (mask\&(1<<i))>0 (mask&(1<<i))>0 and ( m a s k & ( 1 < < j ) ) > 0 (mask\&(1<<j))>0 (mask&(1<<j))>0.

初始化:
d p [ 1 < < i ] [ i ] = x [ i ] ∗ x [ i ] + y [ i ] ∗ y [ i ] , 0 ≤ i ≤ n − 1 dp[1<<i][i]=\sqrt{x[i]*x[i]+y[i]*y[i]},0\leq i\leq n-1 dp[1<<i][i]=x[i]x[i]+y[i]y[i] ,0in1;
其余点为无穷大。

代码:

/* ***********************************************
Author        : VFVrPQ
Created Time  : 三  3/ 4 14:21:47 2020
File Name     : luogu1433吃奶酪.cpp
Problem       : 
Description   : 
Solution      : 
Tag           : 
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
#define DEBUG(x) cout<<x<<endl;
const int N = 17;
const int M = 1e9+7;
const int INF = 1e9+7;
const double eps = 1e-8;

int n;
double x[N], y[N];
double dp[1<<N][N];

double dis(double x1, double y1, double x2, double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        scanf("%lf%lf",&x[i],&y[i]);
    }
    //初始化
    int maxmask = 1<<n;
    for (int mask=0;mask<maxmask;mask++){
        for (int i=0;i<n;i++) dp[mask][i] = INF; // 初始化为极小值
    }
    for (int i=0;i<n;i++) dp[1<<i][i] = dis(0.0,0.0,x[i],y[i]);//走一步的
    for (int mask=0;mask<maxmask;mask++){
        for (int i=0;i<n;i++)if (mask&(1<<i)){
            for (int j=0;j<n;j++)if (mask&(1<<j)){
                if (fabs(dp[mask-(1<<i)][j]-INF)<eps) continue; // 
                dp[mask][i] = min(dp[mask][i], dp[mask-(1<<i)][j] + dis(x[i], y[i], x[j], y[j]));
            }
        }
    }
    double ans = INF;
    for (int i=0;i<n;i++) ans = min(ans, dp[maxmask-1][i]);
    printf("%.2lf\n", ans);
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值