2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest——Problem J Automatic Control Machine

题意:

给定一个mn题意:给定一个mn的01矩阵,然后选取其中的某些行,确保每一列都至少有一个1在选中的行中,求最少选中的行数。的01矩阵,然后选取其中的某些行,确保每一列都至少有一个1在选中的行中,求最少选中的行数。

解题思路:

n<15.纯暴力。利用二进制状态压缩以及bitset去储存数据和与运算

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

你可能感兴趣的:(二进制状压,bitset,暴力)