CodeForces 47D 题解

题解笔记

CF47D Safe(safe.cpp)

时间限制 \(5s\) | 内存限制 \(256M\)

题目描述:

小 A 尝试破解一个保险柜上的密码。他知道这条密码由 \(n\) 个或 \(0\) 或 \(1\) 的数字构成。小 A 为了破解保险箱密码,已经尝试了 \(m\) 次。每次输入密码以后系统都会告诉他一共有几位数字输入对了,但系统不会反馈哪几位是错误的。请你帮小 A 计算还有多少种没有试过的密码,而且这些密码不能与之前试过的自相矛盾。

输入格式:

第一行包含两个整数 \(n\) 和 \(m\) ( \(6 \leq n \leq 35\) , \(1 \leq m \leq 10\) ),它们分别表示密码长度和小 A 已经试过密码的次数,接下来的 \(m\) 行,每行包括一个长度为 \(n\) 的数字串和一个整数,分别代表小 A 本次尝试的密码和系统反退给小 A 的数。

输出格式:

仅有一个整数,表示还有多少种可能的密码不会和之前出现过的密码出现矛盾。

输入输出样例:

样例1输入 样例1输出 样例2输入 样例2输出 样例3输入 样例3输出
6 2
000000 2
010100 4
6 6 3
000000 2
010100 4
111100 0
0 6 3
000000 2
010100 4
111100 2
1

解题思路:

brute force 高于万物!!!

这道题显然是一道暴力,首先数据范围就暗示了这一点,而时间限制竟有 \(5\) 秒之多就可看出这道题的做法是暴力了。但纯暴力肯定是不行的,于是就要进行优化。

正常的暴力思维就是 dfs 所有密码,判断当前密码与已知密码相同位的个数是否满足要求,但这个求两个密码相同位的个数是需要一定时间的,所以我们可以将它在选完每一位密码后都进行一次统计。

但这样也优化不了多少,于是就可以发现,如果选完当前的位之后密码已经不合格了,那就直接 continue ,就可以剪枝掉大量的情况,这样就可以AC了。

参考代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<bitset>
using namespace std;
typedef long long ll;

int n,m,w[13],ans,d[35];
bitset<35> a[13];

void dfs(int r)
{
    if(r==n)
    {
        for(int i=1; i<=m; i++)
        {
            if(d[i]!=w[i]) return;
        }
        ++ans;
        return;
    }
    for(int i=0; i<=1; i++)
    {
        bool flag=0;
        for(int j=1; j<=m; j++)
        {
            d[j]+=a[j][r]!=i;
            if(d[j]>w[j]) flag=1;
        }
        if(flag)
        {
            for(int j=1; j<=m; j++) d[j]-=a[j][r]!=i;
            continue;
        }
        dfs(r+1);
        for(int j=1; j<=m; j++) d[j]-=a[j][r]!=i;
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) cin>>a[i]>>w[i];
    dfs(0);
    printf("%d",ans);
    return 0;
}

posted @ 2021-12-10 23:17  yhang323  阅读(55)  评论(0)    收藏  举报