ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【递归/dp】Acwing1243.糖果(IDA*+步调函数/状态压缩+01背包)

2022-04-19 22:32:51  阅读:113  来源: 互联网

标签:01 int depth state Acwing1243 include col dp


题目

题解

动态规划

用二进制表示每种味道尝了没有,如:一共有五种味道,吃了前三种——00111,吃了五种——11111
每包糖果都可以选或不选
dp(i,j) i代表前i包糖果, j代表所能到达的状态(吃了几种种味)
其实就是01背包问题
dp[i-1][j & (~w[i])]+1 意味着:选这包糖果,从前面未选这包的状态+1包
同时不用担心重复问题
前面:1 2 3
后面:3 4 5
当前:j & (~w[i]) 会把 3, 4,5位上的1化为0,可前面应该是1,2,3位都为1才有的选,但通过这种运算,前面:00001也有的选,00011也有的选,00111也有的选

未状压(数组需要开到100*(2^20)超过百万,内存空间不够)

#include <iostream>
#include <cstring>
using namespace std;

const int N = 110;

int n,m,k;
int dp[N][1000],w[22];

int main()
{
    cin >> n >> m >> k;
    int t;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= k; ++j)
        {
            cin >> t;
            w[i] |= (1 << t-1);
        }
    }
    
    memset(dp,0x3f,sizeof dp);
    
    dp[0][0] = 0;
    int all  = (1 << m)-1;
    
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 0; j <= all; ++j)
        {
            dp[i][j] = min(dp[i-1][j],dp[i-1][j & (~w[i])]+1);
        }
    }
    if(dp[n][all] >= 0x3f3f3f3f)
        cout << -1 << endl;
    else
        cout << dp[n][all] << endl;
    return 0;
}

状压

#include <iostream>
#include <cstring>
using namespace std;

const int N = (1<<20)+10;

int n,m,k;
int dp[N],w[22];

int main()
{
    cin >> n >> m >> k;
    int t;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= k; ++j)
        {
            cin >> t;
            w[i] |= (1 << t-1);
        }
    }
    
    memset(dp,0x3f,sizeof dp);
    
    dp[0] = 0;
    int all  = (1 << m)-1;
    
    for(int i = 1; i <= n; ++i)
        for(int j = all; j >= 0; j--)
        {
            dp[j] = min(dp[j],dp[j & (~w[i])]+1);
        }
    if(dp[all] >= 0x3f3f3f3f)
        cout << -1 << endl;
    else
        cout << dp[all] << endl;
    return 0;
}

IDA*+步调函数

太晚了题解明早更

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 110, M = 1 << 20;

vector<int> col[30];
int log2[M];
int n, m, k;

//返回最右边1的位置,比如说:10100返回4(100)
int lowbit(int x)
{
    return x & -x;
}

//步调函数:返回至少需要再走几步
int h(int state)
{
    int res = 0;
    for(int i = (1 << m) - 1 - state; i; i -= lowbit(i))
    {
        int c = log2[lowbit(i)];
        res ++ ;
        for(auto row : col[c])  i &= ~row;
    }
    return res;
}

bool dfs(int depth, int state)
{
    if(depth == 0 || h(state) > depth) return state == (1 << m) - 1;
    
    //优先选择方案数最少的
    int t = -1;
    //减去当前状态就可以得知缺少哪一种糖果,对剩下的糖果取方案数最少的
    for(int i = (1 << m) - 1 - state; i; i -= lowbit(i))
    {
        int c = log2[lowbit(i)];
        if( t == -1 || col[c].size() < col[t].size())
            t = c;
    }
    
    for(int row : col[t])
        if(dfs(depth-1,state | row))
            return true;
    return false;
}

int main()
{
    cin >> n >> m >> k;
    for(int i = 0; i < m; ++i) log2[1 << i] = i;  //log2可以找出每个1的列数
    for(int i = 0; i < n; ++i)
    {
        int state = 0;
        for(int j = 0; j < k; ++j)
        {
            int c;
            cin >> c;
            state |= 1 << c - 1;
        }
        
        for(int j = 0; j < m; ++j)
            if(state >> j & 1)
                col[j].push_back(state);
    }
    
    //去掉重复的行
    for(int i = 0; i < m; ++i)
    {
        sort(col[i].begin(),col[i].end());
        col[i].erase(unique(col[i].begin(),col[i].end()),col[i].end());
    }
    
    int depth = 0;
    while(depth <= m && !dfs(depth,0)) depth++;
    if(depth > m)  depth = -1;
    cout << depth << endl;
    return 0;
}

标签:01,int,depth,state,Acwing1243,include,col,dp
来源: https://www.cnblogs.com/czy-algorithm/p/16167724.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有