题意
有 n
个物品,每个物品有 m
个特征,每次询问一个特征,求最少多少次能确定所求物品。
Solution:
考点:状压 dp 。
首先不能暴力枚举,这样第二个样例输出 5
。但是它启发我们当某一组特征 cnt[S]=1
时答案是唯一的。 因为决策是变化的,所以考虑设 dp[S][T]
表示当前问了集合 S
的特征,其中集合 T
的答案是 1
的最小询问数。显然当 cnt[S][T]=1
时返回 0
,cnt[S][T]=0
是不合法状态。
时间复杂度 O(m3^m+n2^m)
。
思考:询问顺序是否对答案有影响?
显然是有影响的,因为这个过程不可逆。
输入的时候按十进制输了,导致自闭了一下午。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,cnt[1<<11][1<<11],dp[1<<11][1<<11],a[1<<11];
string s;
vector<int> vec[15];
map<int,bool> mp;
int dfs(int x,int y) {
if(cnt[x][y] <= 1) return 0;
if(~dp[x][y]) return dp[x][y];
int res = 20;
for(int i=0;i<m;i++) {
if((x>>i) & 1) continue;
res = min(res, max(dfs(x | (1<<i), y), dfs(x | (1<<i), y | (1<<i))) + 1);
}
return dp[x][y] = res;
}
int main() {
while(scanf("%d%d",&m,&n) && (n || m)) {
for(int i=0;i<(1<<m);i++) {
for(int j=i;j;j=(j-1)&i) {
cnt[i][j] = 0;
dp[i][j] = -1;
}
dp[i][0] = -1;
cnt[i][0] = 0;
}
for(int i=1;i<=n;i++) {
cin>>s; a[i]=0;
for(int j=0;j<m;j++) {
if(s[j] == '1') a[i] |= 1<<j;
}
for(int j=0;j<(1<<m);j++) {
cnt[j][a[i] & j] ++;
}
}
printf("%d\n",dfs(0,0));
}
}