题意:
给定一个mn题意:给定一个mn的01矩阵,然后选取其中的某些行,确保每一列都至少有一个1在选中的行中,求最少选中的行数。的01矩阵,然后选取其中的某些行,确保每一列都至少有一个1在选中的行中,求最少选中的行数。
解题思路:
n<15.纯暴力。利用二进制状态压缩以及bitset去储存数据和与运算
#include <bits/stdc++.h>
using namespace std;
bitset<500> number[30];
char str[1001];
int main(){
int T;
scanf("%d",&T);
while (T--){
int n,m;
scanf("%d%d",&n,&m);
for (int i=0;i<m;++i){
scanf("%s",str);
number[i]=bitset<500>(str);
}
int len=1<<m;
int ans=m+1;
for (int i=1;i<len;++i){
int t=i;
int s=0;
bitset<500> now(0);
for (int j=0;j<m && t>0;++j){
if (t&1){ now=now|number[j]; s++;}
t>>=1;
}
if (now.count()==n) ans=min(ans,s);
}
if (ans==m+1) printf("-1\n");
else printf("%d\n",ans);
}
}
另一种暴力的写法:直接通过二进制枚举行的子集,然后再一一扫描,判断是否可行。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=555;
char S[N];
int a[22][N],c[22][N],vis[N];
int pw[22],cnt[1010101];
int n,m,T;
int main(){
for (int i=1; i<=20; i++) pw[i]=1<<(i-1);
for (int i=1; i<pw[20]; i++)
cnt[i]=cnt[i/2]+(i&1);
scanf("%d",&T);
while (T--){
scanf("%d%d",&m,&n);
for (int i=1; i<=n; i++) c[i][0]=0;
for (int i=1; i<=n; i++){
scanf("%s",S+1);
for (int j=1; j<=m; j++)
if (S[j]=='1') c[i][++c[i][0]]=j;
}
int ans=1e9;
for (int s=1; s<pw[n+1]; s++){
if (cnt[s]>=ans) continue;
int sum=0;
for (int i=1; i<=m; i++) vis[i]=0;
for (int i=1; i<=n; i++)
if (s&pw[i]){
for (int j=1; j<=c[i][0]; j++)
if (vis[c[i][j]]==0) vis[c[i][j]]=1,sum++;
}
if (sum==m) ans=min(ans,cnt[s]);
}
ans==1e9?printf("-1\n"):printf("%d\n",ans);
}
return 0;
}