首页 > 试题广场 >

小心火烛的歪

[编程题]小心火烛的歪
  • 热度指数:5520 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 512M,其他语言1024M
  • 算法知识视频讲解
\hspace{15pt}小歪正在一个占地 n \times m 大小的草地上研究他的燃放烟花计划。其中,一些位置已经堆放了杂物,为了便于观察,我们将给出一个 n \times m 大小的字符矩阵描述草地。其中,堆放了杂物的位置使用数字 1 标注;其余位置使用数字 0 标注。
\hspace{15pt}小歪已经做好了若干个烟花燃放计划,每一个计划均为一个 n \times m 大小的字符矩阵,一一对应草地的每一个方格。在这个计划中,将会被燃放烟花的地块使用数字 1 标注;没有烟花的地块使用数字 0 标注。
\hspace{15pt}他想选择一些计划同时实施,如果某个地块在任意一个计划中被标注为燃放,那么这个地块就会真的燃放上烟花。小歪想要知道,是否存在这样一种选择方法,使得全部有杂物位置均不会燃放烟花,而没有杂物的位置全部燃放上烟花;如果存在,请输出最少数量的计划。

输入描述:
\hspace{15pt}第一行输入三个整数 n,m,q \left( 1 \leqq n,m,q \leqq 7 \right) 代表草地的长、草地的宽、计划数量。
\hspace{15pt}此后 n 行,每行输入 m 个字符,代表草地初始状态。
\hspace{15pt}此后 n \times q 行,每行输入 m 个字符,用于描述计划。
\hspace{15pt}全部字符仅为数字 \texttt{0}\texttt{1}


输出描述:
\hspace{15pt}如果不存在满足要求的燃放方案,直接输出 -1

\hspace{15pt}否则,请按如下格式输出:
\hspace{15pt}第一行上输出一个整数 p \left( 0 \leqq p \leqq q \right) 代表使用到的计划数量。
\hspace{15pt}第二行输出 p 个整数代表你所选择的计划编号。编号即输入顺序,从 1 开始计数。

\hspace{15pt}如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
示例1

输入

2 2 1
00
01
11
10

输出

1
1
示例2

输入

7 7 5
1110111
1111111
1100001
0101000
1100001
1111111
1110111
0001000
0000000
0000000
1000001
0000000
0000000
0001000
0000000
0000000
0011100
0000000
0011100
0000000
0000000
0000000
0000000
0000010
0000111
0000010
0000000
0000000
0000000
0000000
0010000
0010000
0010000
0000000
0000000
0000000
0000000
0010000
0010111
0010000
0000000
0000000

输出

4
1 2 3 4

说明

\hspace{15pt}草地初始状态如下图所示。在这个样例中,选择 1,2,3,5 也是一个合法的答案。

卧槽,完全没看懂题目想让我干嘛,能不能表达清晰一点
发表于 2025-10-11 20:50:17 回复(0)
我的两个失误:1、没意识到空地可重复放烟花。2、使用递归当遇到在非空地放烟花的情况别直接return,不然后面的方案就不能被考虑到了。
发表于 2025-05-05 20:15:30 回复(0)
这不就是揭幕者们小游戏吗
发表于 2025-11-13 10:40:46 回复(0)
# 将初始状态与计划都转化为数字,通过相加,为0的位置表示没有杂物也没有烟花,通过计划与初始状态依次相加,检查有无‘2’,排除烟花与杂物重合的计划,用itertools.combinations枚举所有的计划组合情况
# 同一个位置可以有多个烟花,因此最后 不能依靠相加后全为‘1’判断,而是是否有‘0’,且由于存在前置‘0’缺失会导致判断出现错误,如‘0001’转化成数字会变成‘1’,因此需要判断字符串长度是否符合
 
importitertools
 
n, m, q = map(int, input().split())
chushi =""
for_ in range(n):
    chushi += input()
 
# 若初始没有0,则不需要计划,输出0
ifchushi.count("0") ==0:
    print(0)
    exit()
 
chushi =int(chushi)
 
jihua = []
for_ in range(q):
    tem =""
    for_ in range(n):
        tem += input()
    jihua.append(int(tem))
 
# 筛选计划,若存在与初始重叠的就排除,找出可行的计划
kexin = {}
fori in range(q):
    ifstr(chushi + jihua[i]).count("2") ==0:
        kexin[i +1] = jihua[i]
 
# 若没有可行的计划或计划没有燃放的位置就输出-1
iflen(kexin) ==0or max(kexin.values()) ==0:
    print(-1)
 
else:
    found = False
    fori in range(1, q +1):
        forfangan in itertools.combinations(kexin.keys(), i):
            shishi = chushi
            forj in fangan:
                shishi += kexin[j]
            # 初始加计划后全部位置都没有空,且长度为n*m防止由于前置0缺失导致原本不可行的方案可行,如001变为1
            ifstr(shishi).count("0") ==0and len(str(shishi)) == n * m:
                print(i)
                print(" ".join(map(str, fangan)))
                found = True
                break
        iffound:
            break

作者:在笔试的柠檬精很不想上
链接:https://www.nowcoder.com/discuss/755840988169383936?sourceSSR=users
来源:牛客网
发表于 2025-05-24 17:23:38 回复(0)
//成功啦 自己做不出来的原因 在于 烟花计划有共同的1!!!即燃放位置  这样是可以的 符合题意 例如例题里那样的  如何解决这个问题 就欧克la

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    private static class plan {
        long mask;
        int id;
        plan(long mask, int id) {
            this.mask = mask;
            this.id = id;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        int m = in.nextInt();
        int q = in.nextInt();
        in.nextLine();
        String[] a = new String[n];//记录草坪原始状态
        for (int i = 0; i < n; i++) {
            a[i] = in.nextLine();
        }
        //对草坪进行目标掩码处理 以及 把杂物位置拿出来
        long targetmask = 0;
        List<int[]> b = new ArrayList<>();
        int pos = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (a[i].charAt(j) == '1') {
                    b.add(new int[] {i, j});
                } else {
                    pos = i * m + j;
                    targetmask = targetmask | 1L << pos;
                }
            }
        }
        //好的方法如下 简洁又易懂
        List<plan> c = new
                ArrayList<>(); //存放满足杂物位置的计划 待排序组合
        for (int i = 0; i < q; i++) {
            List<String> d = new ArrayList<>();
            for (int j = 0; j < n; j++) {
                d.add(in.nextLine());
            }
            boolean NO = false;
            for (int[] k : b) { //遍历放杂物的 获取所有的xy值
                int x = k[0];
                int y = k[1];
                if (d.get(x).charAt(y) == '1') {
                    NO = true;
                    break;
                }
            }
            if (NO) {
                continue;
            }
            //通过的烟花计划开始处理 计算目标掩码 并和id一起存储到类Class中
            long mask = 0;
            for (int j = 0; j < n; j++) {
                String x = d.get(j);
                for (int k = 0; k < m; k++) {
                    if (x.charAt(k) == '1') {
                        pos = j * m + k; //0,0 1,0 0,1  0 1 2  01 10 100
                        mask = mask | 1L << pos;
                    }

                }
            }
            c.add(new plan(mask, i + 1));
        }
        /*
        //这部分是可以的 是自己使用自己的方法找到复合条件烟花计划的 并存储 但是时间上更复杂了 因为等于遍历了所有烟花位置与花坪位置比较 看是否为0  但是上面那个方法只找了杂物位置是否放烟花
        //要把List<int[]> b = new ArrayList<>();修改为 int[][] b = new int[n][m];
        //然后开始筛选烟花计划 排除在杂物中 放烟花计划
        List<plan> c =new ArrayList<>();//存放满足杂物位置的计划 待排序组合
        for(int i = 0;i<q;i++){//有q组
            boolean NO = false;
            long mask = 0;
            pos = 0;
            for(int j = 0;j<n;j++){
                String x = in.nextLine();
                if(NO){
                    continue;
                }
                for(int k = 0;k<m;k++){
                    if(b[j][k]=='1'&&x.charAt(k)=='1'){
                        NO = true;
                        break;
                    }else if(x.charAt(k)=='1'){
                        pos = j*m+k;
                        mask = mask | 1L<<pos;
                    }
                }
            }
            c.add(new plan(mask,i+1));//这里特别注意哦 !!添加成功的烟花计划
        }
        */
        if (targetmask == 0) {
            System.out.println(0);
            return;
        }
        if (c.isEmpty()) { //如果都没有符合的 输出-1并终止程序运行啦
            System.out.println(-1);
            return;
        }        
        //现在我们已经筛选完合适的烟花计划了 该开始组合了 总组合次数= 2^烟花计划次方 -1
        int mincount = Integer.MAX_VALUE;
        List<Integer> minyanhua = null;
        for (int i = 1; i < (1<<c.size()); i++) {
            long mask = 0;
            List<Integer> yanhua = new ArrayList<>();
            for (int j = 0; j < c.size(); j++) {
                if ((i & (1 << j)) != 0) {
                    mask = mask | c.get(j).mask;
                    yanhua.add(c.get(j).id);
                }
            }
            if (mask == targetmask) {
                if (yanhua.size() < mincount) {
                    mincount = yanhua.size();
                    minyanhua = yanhua;
                }
            }
        }//这里遍历组合了所有烟花排序 来看结果 如果都没有 就说明都没有符合的 如果有就输出
        if (minyanhua==null) {
            System.out.println(-1);
        } else {
            System.out.println(mincount);
            for (int i = 0; i < minyanhua.size(); i++) {
                System.out.print(minyanhua.get(i)+" ");
            }
        }
        /*
                System.out.println(targetmask);
                for(int i = 0;i<c.size();i++){
                    System.out.println(c.get(i).mask);
                    System.out.println(c.get(i).id);
                }
                for(int i = 0;i<n;i++){
                    System.out.println(a[i]);
                }

                for(int i = 0;i<n;i++){
                    for(int j = 0;j<m;j++){
                        System.out.print(b[i][j]+" ");
                    }
                    System.out.println();
                }

                */
    }
}
发表于 2025-03-23 23:11:50 回复(3)
#include <array>
#include <bitset>
#include <iostream>
#include <type_traits>
using namespace std;

int main() {
    int n, m, q;
    cin >> n >> m >> q;
    bitset<49> map;
    array<bitset<49>, 7> covers;
    string s, t;
    for (int i = 0; i < n; ++i) {
        cin >> t;
        s += t;
    }
    map = bitset<49>(s);

    for (int i = 0; i < q; ++i) {
        s.clear();
        for (int j = 0; j < n; ++j)
            cin >> t, s += t;
        covers[i] = bitset<49>(s);
    }

    int count = q + 1, ans;
    // 遍历所有可能的cover
    for (int i = 0; i <= 1 << q; ++i) {
        // 如果方案数变多,则直接跳过
        if (__builtin_popcount(i) >= count)
            continue;

        // 将其初始化为全0
        bitset<49> out;
        // 从前向后cover
        for (int j = 0; j < q; ++j) {
            if (i >> j & 1)
                out |= covers[j];
        }
        // 判断是否满足条件
        if ((map | out) == (1LL << m * n) - 1 && (map & out) == 0) {
            count = __builtin_popcount(i);
            ans = i;
        }
    }

    if (count == q + 1)
        count = -1;
    cout << count << endl;
    if (count != -1) {
        for (int i = 0; i < q; ++i)
            if (ans >> i & 1)
                cout << i + 1 << ' ';
    }
}
发表于 2025-03-03 21:54:53 回复(0)
笑死了,有两个测试用例的结果都是找不到方案,结果一个预期输出要求是 -1,另一个预期输出要求是 0,这让我怎么搞?

import sys

# 处理过程用到的数据结构是二维的 bool 块
# 为了理解和思考方便,假设草地为 1 * m (011...)
# 然后这 1 行 bool 可以看成二进制表达的数字
# 那么草地杂物用数字 x 来表示,燃放计划用数字 y 来表示
#
# 想要杂物位置上不能放烟花,而所有空位都放烟花: 
#   就是 x 的所有为 1 的位上,y 必须为 0; 
#   而 x 的所有为 0 的位上,y 必须为 1
#   也就是 x | y == 0b(1111...) 且 x & y == 0
#   那么 y = x ^ 0b(1111...)
# 多个燃放计划一起执行: 
#   那么总计划的值为 yn = y1 | y2 | y3 ...
# 
# 所以这个题目可以简化为:
# 在 y1, y2, y3, ..., yn 中, 找到最少数量的 y (a, b, c...), 使得
#   (ya | yb | yc | ...) == x ^ 0b(1111...) 


# 在 planInfos 中找到能满足 target 的合并的方案
# planInfos: 所有固定的方案
# idx: planInfos 的下标,这个下标前面的方案已经考虑过,后面的方案等待考虑
# clutterInfo: 杂物信息
# target: 所有合并的方案要满足的目标
# mergedInfo: 已经合并好的方案
# planStr: 已选入的所有方案的下标的字符串
#
# return (bool, str): 只要一找到合适的方案,马上就返回
def findPlans(planInfos, idx, clutterInfo, target, mergedInfo, planStr):
    if idx == len(planInfos):
        return (False, '')
    plan = planInfos[idx]
    if plan & clutterInfo != 0: # 这个方案与杂物冲突,直接跳到下一个方案去计算
        return findPlans(planInfos, idx+1, clutterInfo, target, mergedInfo, planStr)

    if plan | mergedInfo == target: # 找到了方案
        return (True, planStr + ' ' + str(idx + 1))

    # 既然要找最少的方案数量,倾向于先不选择当前方案
    b1 = findPlans(planInfos, idx+1, clutterInfo, target, mergedInfo, planStr)
    if b1[0]: return b1

    # 再考虑加上当前的方案
    return findPlans(planInfos, idx+1, clutterInfo, target, mergedInfo | plan, planStr + ' ' + str(idx + 1))

# 提取草地特征,或者提取燃放计划的特征
# 题目说 n, m <= 7, 那么 n * m < 64, 草地信息用 64 位存储就够了,用 int 肯定可以
def extractFeatures(lines: list[str]) -> int:
    feature = 0
    for line in lines:
        for ch in line:
            bit = 1 if ch == '1' else 0
            feature = (feature << 1) + bit
    return feature

n, m, q = map(int, input().split(' '))

clutterInfo = 0
planInfos = [0] * q

for i in range(q + 1):
    lines = []
    for _ in range(n):
        lines.append(input().strip())
    if i == 0:
        # 第一个块是杂物的信息
        clutterInfo = extractFeatures(lines)
    else:
        # 后面的块是烟花信息
        planInfos[i-1] = extractFeatures(lines)

# 全为 1 的草地
allFull = (1 << (n*m)) - 1
target = clutterInfo ^ allFull

res = findPlans(planInfos, 0, clutterInfo, target, 0, '')
if res[0]:
    count = res[1].count(' ')
    print(count)
    print(res[1].strip())
else:
    print(0)

发表于 2025-12-01 23:42:41 回复(0)
What can i say?man ba, out !
发表于 2025-11-29 16:01:30 回复(0)
这道题是简单?瓦特发?
发表于 2025-10-13 13:41:57 回复(0)
普通方法 用回溯,进阶方法 用位运算+状态压缩
import java.util.Scanner;
import java.io.*;

// 数据很小, 回溯枚举检查:可以使用 位运算 + 状态压缩
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] sp = br.readLine().split(" ");
        int n = Integer.parseInt(sp[0]);
        int m = Integer.parseInt(sp[1]);
        int q = Integer.parseInt(sp[2]);
        int[] grass = new int[n]; // 草地n行, 合并每行的宽仅1个数表示
        for (int i = 0; i < n; i++) {
            grass[i] = Integer.parseInt(br.readLine(), 2); // 01字符串转int
        }
        int[][] plans = new int[q][n]; // q个计划
        for (int k = 0; k < q; k++) {
            for (int i = 0; i < n; i++) {
                plans[k][i] = Integer.parseInt(br.readLine(), 2);
            }
        }

        int min = Integer.MAX_VALUE, res = 0;
        next:
        for (int i = 0; i < (1 << q); i++) { // q个计划, [0, 2^q-1]种状态 00..00 ~ 11..11
            int cnt = 0;
            int[]  p = new int[n];
            for (int x = i, k = 0; x > 0; x >>= 1, k++) { 
                if ((x & 1) == 1) { // 对于特定状态i, 二进制1 取计划
                    cnt++;
                    if (!check1(grass, plans[k])) continue next;
                    for (int j = 0; j < n; j++) {
                        p[j] |= plans[k][j];
                    }
                }
            }
            if (check2(grass, p, m)) { // 非杂物部分的0 都填满1
                if (cnt < min) {
                    min = cnt;
                    res = i;
                }
            }
        }

        StringBuilder sb = new StringBuilder(); // 处理结果
        if (min == Integer.MAX_VALUE) {
            sb.append(-1);
        } else {
            sb.append(min).append('\n');
            for (int i = 0; res > 0; i++, res >>= 1) {
                if ((res & 1) == 1) {
                    sb.append(i + 1).append(' ');
                }
            }
        }
        System.out.print(sb.toString());
    }

    // 检查plan没有点燃grass杂物:plan[i] & gras[i]==0
    private static boolean check1(int[] grass, int[] plan) {
        for (int i = 0; i < grass.length; i++) {
            if ((grass[i] & plan[i]) > 0) return false;
        }
        return true;
    }

    // 检查plan填满grass非杂物部分:plan[i] | gras[i]== (1<<m)-1
    private static boolean check2(int[] grass, int[] plan, int m) {
        for (int i = 0; i < grass.length; i++) {
            if ((grass[i] | plan[i]) != (1 << m) - 1) return false;
        }
        return true;
    }
}


发表于 2025-10-09 15:19:43 回复(0)
这是简单题???
发表于 2025-09-19 17:50:47 回复(0)
这个输出不应该是-1吗?为什么会出现0这个结果啊?
发表于 2025-08-25 22:32:01 回复(0)
没找到最小数量,只过了60%的用例,这题真的是简单难度?
using System;
using System.Linq;
using System.Collections.Generic;
public class Program {
    public static void Main() {
        var line = Console.ReadLine ().Split(' ').Select(x => int.Parse(x)).ToList();
        int n = line[0];
        int m = line[1];
        int q = line[2];
        int[,] grass = new int[n, m];// 草地状态、
        int idleNum = 0;
        
        for (int i = 0; i < n; i++) {
            var temp = Console.ReadLine ().Select(x => int.Parse(x.ToString())).ToList();
            for (int j = 0; j < m; j++) {
                grass[i, j] = temp[j];
                if (temp[j] == 0) {
                    idleNum += 1;
                }
            }
        }
        if(idleNum==0){// 检查是否有空位
            Console.WriteLine(0);
            return;
        }
        List<int[,]> plans = new List<int[,]>();
        
        for (int k = 0; k < q; k++) {
            int[,] plan = new int[n, m];// 计划
            bool can=true;// 标识计划是否可被执行
            for (int i = 0; i < n; i++) {
                var temp = Console.ReadLine ().Select(x => int.Parse(x.ToString())).ToList();
                for (int j = 0; j < m; j++) {
                    plan[i, j] = temp[j];// 检查计划是否可执行
                    if(plan[i, j]==1&&grass[i,j]==1){
                        can=false;
                    }
                }
            }
            if(can){
                plans.Add(plan);
            }
            
        }
        bool isEnd = false;
        HashSet<int> res=new HashSet<int>();
        for (int i = 0; i < plans.Count; i++) { // 遍历每一个计划
            if (!isEnd) {
                for (int j = 0; j < n; j++) {
                    for (int k = 0; k < m; k++) { // 遍历计划的每一个位置
                        // 是否等于1,以及草地是否空,是则放置烟花
                        if (plans[i][j, k] == 1 && grass[j, k] == 0&&idleNum>0) {
                            grass[j, k] = 1;
                            res.Add(i+1);
                            idleNum--;
                            if (idleNum == 0) {// 放置完成
                                isEnd=true;
                            }
                        }
                    }
                }
            }else{//
                break;
            }

        }
        if(!isEnd){
            Console.WriteLine(-1);
        }else{
            Console.WriteLine(res.Count);
            Console.WriteLine(string.Join(" ", res));
        }
        //Console.WriteLine(plans.Count);


    }
}


发表于 2025-08-13 23:24:12 回复(0)
不知道示例2明明有5种方案,但答案是4种,并且自己也说有两种解法,及1,2,3,4或1,2,3,5,但就是不合并成5种方法,及1,2,3,4,5,导致我的代码明明可以求出所有方案,但就是过不了用例0。
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n,m,q;
    cin>>n>>m>>q;
    vector<string> v(n);
    int an[100];
    string s;
    for(auto &c:v)cin>>c;
    int sum=0;
    for(int i=0;i<q;i++){
        int f=1;
        for(int j=0;j<n;j++){
            cin>>s;
            bitset<32> b1(s);
            bitset<32> b2(v[j]);
            bitset<32> b3(b1&b2);
            if((b1.count()+b2.count())==b3.count()){
                f=0;
                break;
            }
        }
        if(f){
            sum++;
            an[i]=i+1;
        }
    }
    if(!sum)cout<<-1;
    else{
        cout<<sum<<endl;
        for(int i=0;i<sum;i++)cout<<an[i]<<" ";
    }
}


发表于 2025-08-12 23:36:58 回复(1)
我写的可能有冗余,关键是没想到这烟花会有初始计划直接干草垛和一个坑多个烟花的情况
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m=in.nextInt(),n=in.nextInt(),q=in.nextInt();in.nextLine();
        int [][]grass=new int[m][n];
        for(int i=0;i<m;++i){
            String g1=in.nextLine();
            
            for(int j=0;j<n;++j){
                grass[i][j]=Integer.parseInt(""+g1.charAt(j));
            }
        }
        int [][]an=new int[m][n];
        // int [][]temp=new int[m][n];
        ArrayList<combine> alist=new ArrayList<>();
        for(int k=0;k<q;++k){
            for(int i=0;i<m;++i){
                String g1=in.nextLine();
            for(int j=0;j<n;++j){
                an[i][j]=Integer.parseInt(""+g1.charAt(j));
            }
        }
        alist.add(new combine(m,n,an));
        }
        ArrayList<Integer> listbags=new ArrayList<>();
        for(int i=0;i<q;++i){
            listbags.add(i+1);
        }
        bags(new combine(m,n,grass),new ArrayList<combine>(),alist,new boolean[q],listbags,new combine(m,n,grass));
        int allzero[][]=new int[m][n];
        combine zero=new combine(m,n,allzero);
        for(int i=0;i<q;++i){
            if(isconOk(alist.get(i),new combine(m,n,grass))){
                zero=zero.Numberadd(alist.get(i));
            }
        }
        if(!isFull(m,n,zero.Numberadd(new combine(m,n,grass)))){
            System.out.println(-1);
        }
        else{System.out.println(listbags.size());
        for(int i=0;i<listbags.size();++i){
            System.out.print(listbags.get(i)+" ");
        }}

    }
    private static void bags(combine now,ArrayList<combine> bagsnow,ArrayList<combine> total,boolean used[],ArrayList<Integer>usedbag,combine beginner){
        if(isFull(now.a.length,now.a[0].length,now)&&usedbag.size()>lenused(used)){
            ArrayList<Integer>temp=new ArrayList<>();
            temp=boltoArr(used);
            usedbag.clear();
            usedbag.addAll(temp);return;
        }

        for(int i=0;i<total.size();++i){
            if(!used[i]&&isconOk(total.get(i),beginner)){
                used[i]=true;
                bagsnow.add(total.get(i));
                bags(now.Numberadd(total.get(i)),bagsnow,total,used,usedbag,beginner);
                bagsnow.remove(bagsnow.size()-1);
                used[i]=false;
            }
        }

    }

    private static boolean isconOk(combine a,combine b){
        combine c=a.Numberadd(b);
        for(int i=0;i<c.a.length;++i){
            for(int j=0;j<c.a[0].length;++j){
                if(c.a[i][j]>=2)return false;
            }
        }
        return true;
    }
    private static int lenused(boolean[]used){
        int count=0;
        for(int i=0;i<used.length;++i){
            if(used[i]){
                count++;
            }
        }
        return count;
    }
    private static ArrayList<Integer> boltoArr(boolean[] used){
        ArrayList<Integer> alist=new ArrayList<>();
        for(int i=0;i<used.length;++i){
            if(used[i]){
                alist.add(i+1);
            }
        }
        return alist;
    }
    private static boolean isFull(int m,int n,combine a){
        for(int i=0;i<m;++i){
            for(int j=0;j<n;++j){
                if(a.a[i][j]==0){
                    return false;
                }
            }
        }
        return true;
    }
    
}
class combine{

    int a[][];
    combine(int m,int n,int a[][]){
        int an[][]=new int[m][n];
        for(int i=0;i<m;++i){
            System.arraycopy(a[i],0,an[i],0,n);
            // for(int j=0;j<n;++j){
            //     this.a[i][j]=a[i][j];
            // }
        }
        this.a=an;
    }
    public combine Numberadd(combine b){
        int m=this.a.length,n=this.a[0].length;
        int c[][]=new int[m][n];
        for(int i=0;i<m;++i){
            for(int j=0;j<n;++j){
                c[i][j]=this.a[i][j]+b.a[i][j];
            }
        }
        combine retc=new combine(m,n,c);
        return retc;
    }
}

发表于 2025-08-08 20:48:02 回复(0)
#include <bits/stdc++.h>
//#include <bits/stdc++.h> 引入了几乎所有的标准C++库
//方便后续使用(但会使编译时间较长)

using namespace std;

#define endl "\n"
//#define endl "\n" 用来替代标准的 endl,提高程序的执行效率

int n, m, q;
//n:目标数组 a 的行数
//m:目标数组 a 的列数
//q:可以选择的方案数量

int vis[10];
//vis[10]:记录每个方案是否被选择

int d[10];
//d[10]:存储当前选择的 k 个方案的索引

bool sign;
//sign:标记是否找到了满足条件的方案

vector<string> a(10);
//a:目标数组,每个元素表示该位置是否有烟花或者杂物

/*函数的目的是判断当前选定的 k 个方案的组合,
是否能使得每个位置的烟花和杂物的配置符合特定条件:
即每个位置只能有烟花或杂物,但不能同时有或同时没有*/
void check(vector<vector<string>>& v, int k) {
    //check 函数用于判断当前选择的 k 个方案是否满足特定条件

    vector<vector<int>> temp(n, vector<int>(m, 0));
    /*这个数组用来存储所有选中的方案组合的结果,
    temp 数组的大小与目标数组 a 相同,初始化为 0
    每个元素表示该位置是否放置烟花或杂物(0 或 1)*/

    for (int i = 0; i < k; i++)
        //遍历已选的 k 个方案

        for (int j = 0; j < n; j++)
            //遍历每个行

            for (int p = 0; p < m; p++)
                //遍历每个列

                temp[j][p] |= v[d[i]][j][p] - '0';
    //或运算,计算所有方案得出的结果
    /*temp 是一个二维数组(或 vector<vector<int>> 类型),
    temp[j][p] 表示 temp 中第 j 行第 p 列的元素

    v 是一个三维数组(或三维 vector),
    其中 v[d[i]] 表示第 d[i] 个方案,
    v[d[i]][j][p] 是该方案中第 j 行第 p 列的位置值,
    表示该位置是否有烟花或杂物

    -'0' 是将字符 '0' 的 ASCII 值(即 48)
    从 v[d[i]][j][p] 中减去
    这通常用于将字符数字(如 '1' 或 '0')转换为其对应的整数值
    (例如 '1' 转为 1,'0' 转为 0)
    因此,如果 v[d[i]][j][p] 是字符类型的数字,
    则这一步会将其转为对应的整数值(0 或 1)

    |= 是按位或赋值运算符
    它将 temp[j][p] 和 v[d[i]][j][p] - '0' 按位或,
    并将结果存储回 temp[j][p]
    按位或运算(|)对两个数字的每一位进行操作
    如果两个相应的位中有一个是 1,则结果为 1,否则为 0*/

    sign = 1;
    //变量 sign 初始被设置为 1,表示默认假设条件满足
    //如果后续检测到条件不满足,将会把 sign 设置为 0

    //对每个元素进行检查
    for (int i = 0; i < n; i++) {
        // 遍历二维数组 a 和 temp 的行

        for (int j = 0; j < m; j++) {
            //遍历二维数组 a 和 temp 的列

            if (((a[i][j] - '0') ^ temp[i][j]) != 1) {
                //异或结果不为1
                //说明有杂物的地方会放烟花 或者 没有放杂物的地方却没有放烟花

                /*a[i][j] 是一个字符(例如 '0' 或 '1')
                通过 a[i][j] - '0',
                字符 '0' 被转换为整数 0,字符 '1' 被转换为整数 1
                这通常用于将字符表示的数字转换为整数

                ^ 是按位异或操作符
                异或(^)规则:两个数的对应位相同则结果为 0,不同则结果为 1
                对于两个二进制数 0 和 1,异或结果是 1;
                对于 0 和 0 或 1 和 1,异或结果是 0

                检查目标数组 a 和合并后的 temp 数组的每一个位置
                如果 (a[i][j] - '0') ^ temp[i][j] != 1,
                表示目标数组 a 和 temp 在该位置的值不同,并且异或结果不为 1
                (即相同位置如果一个有杂物另一个有烟花,
                或者没有杂物但没有烟花),
                不满足条件,设置 sign = 0,并退出循环*/

                sign = 0;
                break;
                /*如果找到不满足条件的情况,将 sign 设置为 0,
                并使用 break 语句退出当前的内层循环(即退出列的检查),
                继续进行下一行的检查*/
            }
        }
    }
}

void dfs(vector<vector<string>>& v, int index, int x, int k) {
    //index为当前下标,x为选了多少个方案,k为要选多少个方案

    if (x == k) {
        //如果已选择的方案数x等于需要选的方案数k

        check(v, k);
        //检查是否满足条件

        if (sign) {
            //如果条件满足

            cout << k << endl;
            //输出选取的方案数

            //输出选取的具体方案
            for (int i = 0; i < k; i++)
                cout << d[i] + 1 << " ";
            //将数组中的元素(从0开始的索引)转换成从1开始的数字输出
            //并用空格分隔

            cout << endl;
            return ;
            //满足条件后返回
        }
        return ;
        //如果条件不满足,直接返回

        /*return; 在 C++ 中是一个用于结束函数的语句,
        通常用于没有返回值的函数(即返回类型为 void 的函数)
        它表示函数执行完毕并且不返回任何值*/
    }

    //遍历所有可能的选项,从 index + 1 开始,防止重复选择
    for (int i = index + 1; i < q; i++) {
        if (vis[i] == 0) {
            //如果该选项没有被选择过

            vis[i] = 1;
            //标记该选项已选择

            d[x] = i;
            //记录选项i

            dfs(v, i, x + 1, k);
            //递归搜索下一个选项

            if (sign)return ;
            //如果满足条件,直接返回

            vis[i] = 0;
            //回溯,撤销选择
        }
    }
}
/*递归终止条件:
当 x == k 时,意味着已经选择了 k 个方案,
调用 check(v, k) 检查当前选择的方案是否满足条件

条件满足时的操作:
如果 check 返回 sign 为真(即满足条件),
则输出选择的方案数量和具体的方案(d[i] + 1)

递归遍历:
从 index + 1 开始遍历所有未选中的方案(vis[i] == 0),
标记为已选中(vis[i] = 1),并递归调用 dfs,继续选择下一个方案

回溯:在递归返回后,撤销对方案的选择,回溯到上一步,
继续尝试其他可能的选择*/

void solve() {
    cin >> n >> m >> q;
    //n:目标数组的行数
    //m:目标数组的列数
    //q:可以选择的方案数量

    for (int i = 0; i < n; i++)cin >> a[i];
    //输入目标数组 a,它是一个二维数组,包含烟花和杂物的配置
    //(‘0’表示没有烟花或杂物,‘1’表示有烟花或杂物)

    vector<vector<string>> v(q, vector<string>(n));
    //创建一个三维的数组 v
    //用于存储所有 q 个方案的配置,每个方案是一个二维数组

    for (int i = 0; i < q; i++)
        for (int j = 0; j < n; j++)
            cin >> v[i][j];
    //这个双层循环用于从输入中读取 q 个方案,每个方案是一个 n 行的数组
    //v[i][j] 表示第 i 个方案中第 j 行的元素

    //特判全1的情况,这种情况输出0而不是-1
    sign = 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (a[i][j] == '0') {
                //检查目标数组 a 中是否存在 '0'

                sign = 0;
                //如果 a[i][j] == '0',则将 sign 设为 0

                break;
                //并跳出当前循环
            }
            //整个目标数组 a 被遍历,如果找到了 '0',就说明不是全 '1'
        }
        if (!sign)break;
        //如果在外层循环中发现 sign 已经变为 0(即找到了 '0')
        //则直接跳出外层循环,不再继续遍历
    }
    if (sign) {
        cout << 0;
        return ;
    }
    //如果 sign 为 1(即目标数组 a 中所有元素都是 '1')
    //则输出 0,并结束当前函数

    /*如果目标数组 a 中的所有元素都是 '1',
    那么直接输出 0,表示不需要选择任何方案*/

    for (int i = 1; i <= q; i++) {
        //选一种方案,选两种方案...... q 种方案全选,遍历

        for (int j = 0; j < q; j++)vis[j] = 0;
        //在每次开始新的 i 个方案的尝试之前,将访问标志数组 vis 重置为 0
        //vis[j] 用来标记是否已经访问过第 j 个方案

        dfs(v, -1, 0, i);

        if (sign)return;
        /*sign 是一个标志变量,用来表示当前方案是否有效
        如果 dfs 找到了一个有效的方案,
        sign 被设置为 true,
        并且会退出当前的 for 循环*/
    }
    cout << -1 << endl;
    /*从选择一种方案开始,逐步增加选项数目,直到选择 q 种方案

    对每一种方案组合,
    调用 dfs() 函数进行递归搜索,
    检查当前选择的组合是否符合条件

    如果找到符合条件的组合,
    dfs() 会通过 sign 标记为 true,
    并且函数会提前返回

    如果在所有方案组合中都没有找到满足条件的组合,最终输出 -1*/
}

signed main() {
    //signed main() 是主函数的声明
    //signed 是一个修饰符,通常用于整数类型变量来表示其为有符号(signed)

    ios::sync_with_stdio(0);
    /*关闭了 C++ 标准库和 C 标准库之间的同步
    C++ 的 iostream(例如 cin, cout)和
    C 的 stdio(例如 scanf, printf)默认是同步的,
    为了兼容 C 和 C++ 的输入输出操作

    这种同步会导致性能下降,特别是在大量输入输出时

    通过 ios::sync_with_stdio(0) 禁用同步,
    可以显著提高程序的输入输出速度*/

    cin.tie(0);
    /*解除 cin 和 cout 之间的绑定
    默认情况下,cin 会在每次读取输入之前自动刷新 cout,
    这会增加一些不必要的操作,导致性能降低
    使用 cin.tie(0) 可以让 cin 不再和 cout 绑定,从而提高效率*/

    cout.tie(0);
    /*解除 cout 和 cin 之间的绑定,作用与 cin.tie(0) 类似
    它确保在输出之前不会不必要地刷新输入流,从而提高程序的输出性能*/

    int t;
    t = 1;
    //声明了一个整型变量 t,并将其初始化为 1
    //cin>>t;

    while (t--)
        solve();
    /*这一行是一个循环语句,表示循环执行 solve() 函数,循环的次数是 t
    t-- 表示先执行 solve() 函数,然后 t 减少 1
    由于 t 被设置为 1,所以这个循环只会执行一次,
    调用 solve() 函数来处理单个测试用例*/
}

发表于 2025-07-19 02:30:34 回复(0)
import itertools
import sys
n_m_q = input().split()
n = int(n_m_q[0])
m = int(n_m_q[1])
q = int(n_m_q[2])

# 初始草坪状态
m_ori = []
for i in range(n):
    s = input()
    row = [int(i) for i in s]
    m_ori.append(row)

# 如果全被杂物占据,输出0,退出
no_space = True
for row in m_ori:
    for i in row:
        if i<1:
            no_space = False
if no_space:
    print(0)
    sys.exit()

# 记录所有plan
plans = []

for i in range(q):
    curr_plan = []
    for j in range(n):
        s = input()
        curr_row = [int(i) for i in s]
        curr_plan.append(curr_row)
    plans.append(curr_plan)

# 排除在杂物上放烟花的plan,即某个位置在plan和ori都为1
ok_index = []
for k in range(q):
    flag_ok = True
    for i in range(n): # row
        for j in range(m):  # item
            if plans[k][i][j] and m_ori[i][j] == True:
                flag_ok = False
                break
        if not flag_ok:
            break
    if flag_ok:
        ok_index.append(k)

if len(ok_index)<1:
    print(-1)
    sys.exit()

# 将m_ori取反,方便后续比对
for i in range(n):
    for j in range(m):
        if m_ori[i][j]==0:
            m_ori[i][j] =1
        else:
            m_ori[i][j] =0

# 矩阵相加
def add_mat(m1,m2,n,m):
    m_output = [[0]*m for _ in range(n)]
    for i in range(n):
        for j in range(m):
            if m1[i][j] or m2[i][j]:
                m_output[i][j] = 1
    return m_output

# 得到所有可能的plan组合
all_comb = []
for r in range(1, len(ok_index)+1):
    all_comb.extend(itertools.combinations(ok_index,r))
all_comb = [list(comb) for comb in all_comb]

#print(all_comb) # 组合列表长度由短到长
find = False
ok_comb_index = []
for comb in all_comb:
    plan_comb = [[0]*m for _ in range(n)]
    for index in comb:
        plan_comb = add_mat(plan_comb,plans[index],n,m)
    if plan_comb == m_ori:
        ok_comb_index = comb
        find = True
        break
if not find:
    print(-1)
    sys.exit()

print(len(ok_comb_index))
s_comb = [str(i+1) for i in ok_comb_index]
print(' '.join(s_comb))
发表于 2025-07-18 14:17:11 回复(0)
from itertools import combinations
n, m, q = map(int, input().split())
cond = []
sum_cond = 0
for i in range(n):
    temp = list(map(int, list(input())))
    sum_cond += sum(temp)
    cond.append(temp)

plan = []
avail = []
for i in range(q):
    plan_ = []
    avail_ = 1
    for j in range(n):
        temp = list(map(int, list(input())))
        plan_.append(temp)
        if 2 in [temp[k]+cond[j][k] for k in range(m)]:
            avail_ = 0
    plan.append(plan_)
    if avail_:
        avail.append(i)

def is_valid(plan, comb, cond):
    temp = cond.copy()
    for p in range(len(comb)):
        plan_ = plan[comb[p]]
        for i in range(n):
            temp[i] = [temp[i][j]+plan_[i][j] for j in range(m)]
    for i in range(n):
        if 0 in temp[i]:
            return False
    return True

if sum_cond == n*m:
    print(0)
else:    
    sum = cond.copy()
    for i in range(n):
        for j in range(q):
            if j in avail:
                sum[i] = [sum[i][k] + plan[j][i][k] for k in range(m)]
               
    unavail = 0
    for i in range(n):
        if 0 in sum[i]:
            unavail = 1
            break

    found = 0
    if unavail == 1:
        print(-1)
    else:
        for num in range(1, 1+len(avail)):
            for comb in combinations(avail, num):
                if is_valid(plan, comb, cond):
                    print(num)
                    print(' '.join(map(str, [comb[i]+1 for i in range(len(comb))])))
                    found = 1
                    break
            if found == 1:
                break


发表于 2025-07-18 00:44:02 回复(0)
n,m,q = list(map(int,input().split()))
A = [list(map(int,input())) for _ in range(n)]
all_ones = True
for row in A:
    if any(bit == 0 for bit in row):
        all_ones = False
        break
if all_ones:
    print(0)
    exit()
target_bits = []
for row in A:
    bits = 0
    for bit in row:
        bits = (bits<<1) | (1-bit)    #取反:0->1,1->0
    target_bits.append(bits)
valid_meth = []
meth_bits = []
for i in range(q):
    meth_q = [list(map(int,input())) for _ in range(n)]
    is_valid = True
    for row in range(n):
        for col in range(m):
            if A[row][col] == 1 and meth_q[row][col] == 1:
                is_valid = False
                break
        if not is_valid:
            break
    if is_valid:
        valid_meth.append(i)
        mbits = []
        for row in meth_q:
            bits = 0
            for bit in row:
                bits = (bits << 1) | bit  #保存满足要求的矩阵
            mbits.append(bits)
        meth_bits.append(mbits)   #多个矩阵列表
if not valid_meth:
    print(-1)
else:
    from itertools import combinations
    min_count = float('inf')
    best_comb = []
    best_combs = []
    for r in range(1,len(valid_meth) + 1):
        for comb in combinations(range(len(valid_meth)),r):
            union = [0] * n  #每个元素表示一行的覆盖情况
            for idx in comb:
                mbits = meth_bits[idx]  #获取子矩阵的二进制表示
                for j in range(n):
                    union[j] |= mbits[j]  
            cover_all = True
            for j in range(n):
                if (union[j] & target_bits[j]) != target_bits[j]:
                    cover_all = False
                    break
            if cover_all:
                if r < min_count:
                    min_count = r
                    best_combs = [[valid_meth[i] for i in comb]]
                elif r == min_count:
                    best_combs.append([valid_meth[i] for i in comb])  # 添加新组合   
                    break
        if min_count != float('inf'):
            break
    if min_count == float('inf'):
        print(-1)
    else:
        print(min_count)
        print(' '.join(map(lambda x: str(x + 1), sorted(best_combs[0]))))

发表于 2025-06-19 10:45:11 回复(0)
感觉这个题目说的不清不楚的
发表于 2025-06-17 09:27:06 回复(0)