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;
}

浙公网安备 33010602011771号