一、题目:
二、样例输入输出:
(1)输入
3 4
1000
0101
1011
2
1001
0011
(2)输出
1
-1
2
三、思路
运用二进制的存储方式病人的身体状况,药材的治疗功效,利用二进制来枚举所有2^k方式——要不要取药材(!!!非常巧妙-我没想到呜呜)
四、具体代码
代码上面有注释,我感觉还是比较详细的
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
int res=INT_MAX;
int main(void){
int n,m;
cin>>n>>m;
string s;
vector<int> a(n,0); //vector容器开辟了长度为n的数组,并将它们初始化为0
for(int i=0;i<n;i++){
cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='1'){
//将病人的身体状态以二进制的形式存起来
a[i]|=1<<j;
}
}
}
int k;
cin>>k;
vector<int> b(k,0);
for(int i=0;i<k;i++){
cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='1'){
//将每个药物的治疗功效以二进制的形式存起来
b[i]|=(1<<j);
}
}
}
for(int i=0;i<n;i++){ //遍历每个病人
//我们可以用二进制的形式来表示m个药物取或者不取,0表示不取,1表示取
//则有我们可以把1左移k位
//比如:k=2,我们把1左移两位得到100,0-100里面包括00,01,10,11
//刚好包含所有情况
res=INT_MAX;
for(int t=0;t<(1<<k);t++){
int x=0,num=0;
//遍历每种药材执行取或者不取
for(int j=0;j<k;j++){
//t>>j是为了看第j个药材是取还是不取的状态
if((t>>j)&1){
//得到取的指令,用x存下来,有取多个药材的时候用x得到他们全部合并后的结果
x|=b[j];
//把取药材的数量记录下来
num++;
}
if((x&a[i])==a[i]) //x&a[i]表示我把x与a[i]取交集,都为1的取1,
//只有一个为1或者都为0的取0
//如果取交集得到的结果和a[i]相同,那么说明该病人能够通过num个药物得到医治
//再和之前的最少药材进行比较,看是否需要更新最小值
res=min(num,res);
}
}
if(res==INT_MAX){
printf("-1\n");
}
else{
printf("%d\n",res);
}
}
return 0;
}
简便写法:
#include <iostream>
using namespace std;
int a[10005], b[15], c[1024];
int main() {
int n,m,k;
cin>>n>>m;
string s;
for (int i=1; i<=n; i++)
cin>>s, a[i] = stoi(s, 0, 2);
cin>>k;
for (int i=0; i<k; i++)
cin>>s, b[i] = stoi(s, 0, 2);
for (int j=1; j<(1<<k); j++)
for (int i=0; i<k; i++)
if (j>>i&1)
c[j] |= b[i];
for (int i=1; i<=n; i++) {
int mi = k+1;
for (int j=0; j<(1<<k); j++)
if ((c[j]&a[i]) == a[i])
mi = min(mi, __builtin_popcount(j));
if (mi == k+1)
cout<<-1<<'\n';
else
cout<<mi<<'\n';
}
return 0;
}
stoi函数用法参考:C++ stoi( )-优快云博客
_builtin_popcount函数用法参考:
C语言popcount函数,C/C++中__builtin_popcount()的使用及原理详解-优快云博客
看懂的话点个小赞支持一下我吧嘻嘻嘻