记忆化搜索,状压DP(20个问题,uva 1252)

本文探讨了一种利用动态规划解决特定问题的方法,通过定义合理的决策与状态来优化求解过程。介绍了如何通过记忆化搜索避免重复计算,并给出具体的状态转移方程。代码示例展示了如何实现这一算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要学会找到“决策”和“状态”。

在这题中,“决策”无非就是问哪个问题,而问过的问题就不能再问了,因此需要已问过哪些问题的“状态”。每次询问,无非得到两个结果,是或不是,所以还需要“状态”:问过的问题中,那些得到了肯定的回答。问问题的顺序不会影响结果,因此需要记忆化搜索。


状态转移方程: ans=min(ans,max(dp(s|(1<<i),a),dp(s|(1<<i),a|(1<<i)))+1);


题目要求找最少问几次保证问出。

保证问出:显然有的物品问一次就知道了,而有的可能要问很多次,为了保证任何物品都能问出,所以要取最大值。观察状态转移方程,每问一次,结果无非是“是”或“否”,无论是哪种结果,都一定对应着一个物品,为了保证他们都能问出来,所以选大的那个。

最少问几次:对于任何物品,有些问题是没必要问的,所以要取最小值。观察状态转移方程,对于单次询问,你问啥都是OK的,反正最终你一定能问到答案,关键是你的问题是否有必要问,我们在众多问法中选择一个次数最小的问法一定是最优的。


代码

#include<bits/stdc++.h>
#define maxn 150
#define INF 0X3F3F3F3F
using namespace std;

int m,n;
int tx[maxn];
int d[1<<11][1<<11];
int cnt[1<<11][1<<11];
char str[maxn];

int dp(int s,int a)
{
    if(cnt[s][a]<0)
    {
        int CNT=0;
        for(int i=0;i<n;i++)
            if((tx[i]&s)==a) CNT++;
        cnt[s][a]=CNT;
    }
    int& ans=d[s][a];
    if(ans>=0) return ans;
    if(cnt[s][a]==1) ans=0;
    else
    {
        ans=INF;
        for(int i=0;i<m;i++)
            if(((1<<i)&s)==0)
                ans=min(ans,max(dp(s|(1<<i),a),dp(s|(1<<i),a|(1<<i)))+1);
    }
    return ans;
}

int main()
{
    while(scanf("%d %d",&m,&n),m+n)
    {
        memset(d,-1,sizeof(d));
        memset(tx,0,sizeof(tx));
        memset(cnt,-1,sizeof(cnt));
        for(int i=0;i<n;i++)
        {
            scanf("%s",str);
            for(int j=0;j<m;j++)
                if(str[j]=='1')
                    tx[i]|=1<<j;
        }
        printf("%d\n",dp(0,0));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值