HDU 1438 钥匙计数之一(记忆化搜索)

版权声明:没人会转的( ̄▽ ̄) https://blog.csdn.net/j2_o2/article/details/85871695
题目链接
题意,别的语言不会,翻译不能。

一把锁匙有N个槽,槽深为1,2,3,4。每锁匙至少有3个不同的深度且至少有1对相连的槽其深度之差为3。求这样的锁匙的总数。

思路

网上多是 线性递推或者状压dp的,这里用记忆化搜索试试,虽然感觉这种搜索和数位dp比较相似。


dp[35][2][100][5]; 第几位,存在差为3,出现种类数量,上个值


dfs(pos, limit, num, la)
pos 当前位置
limit 是否存在差值大于3
num 种类,不好记录随便用二进制前四位表示,反正内存大时间还挺快
la 上一位是什么
dp数组和dfs传参写完基本完成一半了,下面看代码吧

代码
#include <bits/stdc++.h>
using namespace std;

#define ll long long

ll dp[35][2][100][5]; // 第几位 存在差为3 出现种类数量 上个值

inline ll abso(ll a)
{
    return a < 0 ? -a : a;
}

inline ll ge(ll a) // 得到二进制中1的数量,即种类
{
    ll cnt = 0;
    while(a)a&=(a-1), ++cnt;
    return cnt;
}

/*
pos 当前位置
limit 是否存在差值大于3
num 种类,不好记录随便用二进制前几位表示,反正内存大时间还挺快
la 上一位是什么
*/

// la第一次传2可以对 limit 无影响,且由于num=0必定不会影响后面记忆化搜索
ll dfs(ll pos, ll limit, ll num, ll la)
{
    if(!pos) return limit && ge(num) > 2;
    ll tmp = 0;
    if(~dp[pos][limit][num][la]) return dp[pos][limit][num][la];
    for(ll i = 1; i <= 4; ++i) tmp += dfs(pos-1, limit || abso(i-la)>2, num|(1<<i), i);
    return dp[pos][limit][num][la] = tmp;
}

int main()
{
    memset(dp,-1,sizeof(dp));
    for(ll n = 2; n <= 31; ++n) printf("N=%lld: %lld\n",n,dfs(n,0,0,2));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/j2_o2/article/details/85871695