二进制枚举+思维 牛客小白月赛23 A题 膜法记录

膜法记录

题目描述

牛牛最近在玩一款叫做《膜法记录》的游戏,这个游戏的机制是这样的:
在一局游戏中,所有的敌人都排布在一个 n 行 m 列的网格中,牛牛指挥着他的魔法少女对敌人进行攻击。
攻击有两种类型:行blast,列blast
行blast能消灭一整行的敌人,列blast能消灭一整列的敌人
牛牛总共能够释放 a 次行blast,b 次列blast
给定某局游戏的初始局面,请问牛牛能否将敌人全歼?

输入描述:

第一行包含一个正整数T,表示测试数据组数,接下来是T组测试数据
每组测试数据的第一行有四个正整数 n,m,a,b
接下来有n行,每行是一个长度为m的字符串,第i行第j列的字符如果是*则说明这里有一个敌人,如果是.说明这里没有

输出描述:

对每组测试数据输出一行,如果能消灭所有的敌人,就输出yes,否则输出no


先说一下,这道题的数据可能有些问题;要考虑a=0的情况;

非常思维的一道题;

首先要想到可以二进制枚举行,预处理取第 i 个二进制数(也就是行的组合),消除这些行,所消除的列数,记为cnt[i];然后剩下的列数就为 m-cnt[i];

怎么预处理是这道题的关键,先枚举列从1–m,然后对每一列的敌人所在的行的位置进行处理,传化为一个二进制数;每一个二进制数代表这一列敌人行的排布;那么cnt[i]表示排列为 i 的敌人列数;

还有个处理,例如:11011的排列,相当于我们必须取1,2,4,5行才可以把敌人消灭,但是我们取1.2.4.5时也把11010、11000等等都消灭了,所以还要找到每一个二进制数的1重的排列数。应该可以自己理解这个;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100100;
const int M=2000100;
const LL mod=100000000;
int n,m,a,b,cnt[M];
char s[25][N];
int sum_1(int p){
    int ans=0;
    while(p){
        if(p%2) ans++;
        p/=2;
    }
    return ans;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>m>>a>>b;
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
        for (int i = 0; i < (1<<n); i++) cnt[i] = 0;
        for(int j=1;j<=m;j++){
            int t=0;
            for(int i=1;i<=n;i++){
                if(s[i][j]=='*') t|=(1<<i-1);//t代表第i列有哪几行有敌人
            }
            cnt[t]++;//相同列的个数
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<=(1<<n)-1;j++){
                if((j&(1<<i-1))==0){//这个表示数j的第i个二进制位为0
                    cnt[j|(1<<i-1)]+=cnt[j];//表示第i个二进制位为1的数加上cnt[j]
                }
            }
        }
        bool ok=false;
        for(int i=0;i<(1<<n);i++){
            if(sum_1(i)<=a&&m-cnt[i]<=b) ok=true;
        }
        if(ok) cout<<"yes"<<endl;
        else cout<<"no"<<endl;
    }	
    return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/105036705
今日推荐