AcWing
  • 首页
  • 活动
  • 题库
  • 竞赛
  • 应用
  • 其它
    • 题解
    • 分享
    • 商店
    • 问答
  • 吐槽
  • 登录/注册

AcWing 1243. 糖果    原题链接    中等

作者: 作者的头像   热的干面 ,  2023-01-25 21:59:25 ,  所有人可见 ,  阅读 21


0


package lanqiao_day01;

import java.io.*;
import java.math.BigDecimal;
import java.time.Year;
import java.util.*;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer in = new StreamTokenizer(br);
    static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));

    public static int nextInt() throws Exception {
        in.nextToken();
        return (int) in.nval;
    }

    public static double nextDouble() throws Exception {
        in.nextToken();
        return in.nval;
    }

    public static long nextLong() throws Exception {
        in.nextToken();
        return (long) in.nval;
    }

    public static String nextStr() throws Exception {
        in.nextToken();
        return in.sval;
    }

    public static String nextLine() throws Exception {
        return br.readLine();
    }

    static int n, m, k;
    static int N = 110;
    static int M = 1 << 20;
    static int[] log2 = new int[M];
    //使用set去重,优化速度
    static Set[] col = new HashSet[21];
    public static void main(String[] args) throws Exception {
        n = nextInt();
        m = nextInt();
        k = nextInt();

        for (int i = 0; i < m; i++) {
            col[i] = new HashSet<Integer>();
            //获取log2数组,方便之后根据数值得出二进制上哪一位是1
            log2[1 << i] = i;
        }
        //读取n个糖果
        for (int i = 0; i < n; i++) {
            //使用二进制数表示当前这包糖果有哪些糖
            int state = 0;
            for (int j = 0; j < k; j++) {
                int c = nextInt();
                //或运算,例如c=5,1左移四位之后对state进行或运算,state的第五个数会变为1
                state |= 1 << c - 1;
            }
            //当前这包糖果已经全部读完,将其添加到对应的糖果种类数组里
            for (int k = state; k > 0; k -= lowbit(k)) {//lowbit返回最后一个1的数值,例如10010会返回10
                int c = log2[lowbit(k)];//获取对应哪一种糖果
                col[c].add(state);
            }
        }
        //迭代加深,不断去扩大depth的值
        int depth = 1;
        while (depth <= m && !dfs(depth, 0)) {
            depth++;
        }
        //不满足对应的要求,depth最多取m个,如果大于m个就代表没有结果
        if (depth > m)
            depth = -1;
        System.out.println(depth);
    }
    //递归过程
    private static boolean dfs(int depth, int state) {
        //糖果已经拿完或者最少要拿多少包糖果大于当前剩余的数量
        if (depth <= 0 || h(state) > depth)
            return state == (1 << m) - 1;

        int t = -1;
        // 找到选择性最小的一列,就是说包含该糖果种类的糖果包数量最少
        //(1 << m) - 1 -state代表当前还有那些种类没有选择
        for (int i = (1 << m) - 1 -state; i > 0; i -= lowbit(i)) {
            int c = log2[lowbit(i)];
            //比较长度
            if (t == -1 || col[t].size() > col[c].size()) {
                t = c;
            }
        }
        // 枚举选哪行
        Set<Integer> set = col[t];
        for(int row : set) {
            if (dfs(depth - 1, state | row)) {
                return true;
            }
        }
        return false;
    }

    // 求一下最少需要再选几包糖果
    private static int h(int state) {
        int res = 0;
        for (int i = (1 << m) - 1 - state; i > 0;) {
            int c = log2[lowbit(i)];
            res++;
            Set<Integer> set = col[c];
            for(int row : set) {
                i &= ~row;
                //将row这包糖果对应的糖果种类中的1全部变成0,~取反,在配上&能实现对应的效果
            }
        }
        return res;
    }
    private static int lowbit(int i) {
        return i & -i;
    }

}

0 评论

你确定删除吗?
1024
x

© 2018-2023 AcWing 版权所有  |  京ICP备17053197号-1
用户协议  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息