其他分享
首页 > 其他分享> > M - Little Pony and Harmony Chest 状压dp

M - Little Pony and Harmony Chest 状压dp

作者:互联网

M - Little Pony and Harmony Chest

 怎么感觉自己越来越傻了,都知道状态的定义了还没有推出转移方程。

首先这个a的范围是0~30   这里可以推出 b数组的范围 0~60

原因很简单,因为这个要求abs(b-a)) 尽量小,所以如果b>=60 那还不如用1 ,因为1 的数量是没有限制的,

当 b>60 abs(b-a)>30 所以相比 b>60 b==1 更优。

然后我们对质数进行状压,为什么要对质数进行状压呢,因为质数两两互质,而且每一个数都是由若干个质数组成。

所以我们可以用质数来对状态进行筛选。

因为b的范围是从1到58(如果要选59,则也可以选1),所以我们要打个表,来表示他是由哪些素数组成的。

为什么要这样呢,因为这样可以就可以快速判断出之前的状态是不是和这个有冲突(就是有没有相同的质数)

知道这些就差不多了,这个题目利用状压位运算来判断一个两两之间有没有公约数,方法很巧妙。

具体:

dp[i][s] 表示到第 i 个位置,之前的状态为 s 的最小代价,

初始化 dp[0][0]=0,其他都是不合理的状态,所以初始化为inf

首先枚举位置,其次枚举状态,然后在枚举这个位置所有可能的数。

路径的输出就是记录这个状态的放的数,和这个状态之前的状态,一个是记录状态一个是记录数。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
typedef long long ll;
ll dp[102][1<<17];
int is[102][1<<17];
int pre[102][1<<17];
int p[maxn], isp[maxn], m;
void init()
{
    memset(p, 0, sizeof(p));
    for (int i = 2; i <= 100; i++) p[i] = 1;
    for(int i=2;i*i<=100;i++)
    {
        if(p[i])
        {
            for(int j=i*i;j<=100;j+=i)
            {
                p[j] = 0;
            }
        }
    }
    m = 0;
    for(int i=1;i<=100;i++)    if (p[i]) isp[++m] = i;
}
int sta[100], a[110];
vector<int>e;
int main()
{
    int n; init();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int i=2;i<=60;i++)
    {
        for(int j=1;j<=17;j++)
        {
            if (i%isp[j] == 0) sta[i] |= (1 << (j - 1));//sta 数组表示选i这个数的限制条件,这个要好好理解。
        }
    }
    memset(pre, -1, sizeof(pre));
    memset(dp, inf64, sizeof(dp));
    dp[0][0] = 0;//这个dp定义的是到第i个位置,数的状态为s的代价,
    //如果dp == inf  说明是不合理的状态,因为如果是在0这个位置,所以当没有数的状态就是合理的而且代价==0
    for(int i=0;i<n;i++)//这个从0 开始是因为每次第i个更新第i+1个
    {
        for(int j=0;j<(1<<17);j++)
        {
            if (dp[i][j] == inf64) continue;
            for(int k=1;k<=60;k++)
            {
                if (sta[k] & j) continue;
                int tmp = sta[k] | j;
                if (dp[i + 1][tmp] > dp[i][j] + abs(a[i+1] - k))
                {
                    dp[i + 1][tmp] = dp[i][j] + abs(a[i+1] - k);
                    is[i + 1][tmp] = k;
                    pre[i + 1][tmp] = j;
                }
            }
        }
    }
    int ans=inf, id=0;
    for(int i=0;i<(1<<17);i++)
    {
        if(dp[n][i]<ans)
        {
            ans = dp[n][i];
            id = i;
        }
    }
    for(int i=n;i>=1;i--)
    {
        e.push_back(is[i][id]);
        id = pre[i][id];
    }
    for (int i = e.size() - 1; i >= 0; i--) printf("%d ", e[i]);
    printf("\n");
    return 0;
}
状压dp

 

标签:状态,Little,Pony,int,质数,状压,abs,include,dp
来源: https://www.cnblogs.com/EchoZQN/p/11255774.html