糖果 蓝桥杯 重复覆盖问题 搜索
Published on 2022-11-17 23:03 in 暂未分类 with 林动

糖果 蓝桥杯 重复覆盖问题 搜索

    糖果店的老板一共有 M 种口味的糖果出售。

    为了方便描述,我们将 M 种口味编号 1∼M。

    小明希望能品尝到所有口味的糖果。

    遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。

    幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。

    给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

    输入格式
    第一行包含三个整数 N,M,K。

    接下来 N 行每行 K 这整数 T1,T2,⋅⋅⋅,TK,代表一包糖果的口味。

    输出格式
    一个整数表示答案。

    如果小明无法品尝所有口味,输出 −1。

    数据范围
    1≤N≤100,
    1≤M,K≤20,
    1≤Ti≤M
    输入样例:
    6 5 3
    1 1 2
    1 2 3
    1 1 3
    2 3 5
    5 4 2
    5 1 2
    输出样例:
    2

    搜索的3个优化点

    1.迭代加深(最重要的优化点)
    每次以确定的迭代深度去尝试,不行再换更高的深度,但是深度也有界限,比如这个题目中深度最多为m,否则肯定无解了。

    2.可行性剪枝

    3.每次迭代找可选择性最少的列

    import java.util.*;
    
    public class Main
    {
    	static int n,m,k;
    	static int N=105,M=1<<20;
    	static int log2[]=new int[M];
    	static Vector col[]=new Vector [N];
    	
    	static int lowbit(int x)
    	{
    		return x&-x;
    	}
    	// 最少需要再选几行  可行性剪枝
    	static int h(int state)
    	{
    		int res=0;
    		for(int i=(1<<m)-1-state;i!=0;i-=lowbit(i))
    		{
    			int c=log2[lowbit(i)];
    			res++;
    			for(int j=0;j<col[c].size();++j)
    			{
    				int row=(int)col[c].get(j);
    				i&=~row;
    			}
    			
    		}
    		return res;
    	}
    	static boolean dfs(int depth, int state)
    	{
    		if(depth==0||h(state)>depth)return state==(1<<m)-1;
    		
    		// 找到选择性最少的一列
    		int t=-1;
    		for(int i=(1<<m)-1-state;i!=0;i-=lowbit(i))
    		{
    			int c=log2[lowbit(i)];
    			if(t==-1||col[c].size()<col[t].size())t=c;
    		}
    		
    		// 枚举选哪行
    		for(int i=0;i<col[t].size();++i)
    		{
    			int row=(int) col[t].elementAt(i);
    			if(dfs(depth-1,state|row)==true)
    				return true;
    		}
    		return false;
    	}
    	
    	public static void main(String args[])
    	{
    		Scanner sc=new Scanner(System.in);
    		n=sc.nextInt();
    		m=sc.nextInt();
    		k=sc.nextInt();
    		
    		for(int i=0;i<m;++i)log2[1<<i]=i;
    		for(int i=0;i<m;++i)col[i]= new Vector<>();
    		
    		for(int i=0;i<n;++i)
    		{
    			int state=0;
    			for(int j=0;j<k;++j)
    			{
    				int c;
    				c=sc.nextInt();
    				state|=1<<(c-1);
    			}
    			for(int j=0;j<m;++j)
    			{
    				if(((state>>j)&1)==1)
    				{
    					col[j].addElement(state);
    				}
    			}
    		}
    		
    		//迭代加深
    		int depth=0;
    		while(depth<=m&&dfs(depth,0)==false)depth++;
    		
    		if(depth>m)depth=-1;
    		
    		System.out.println(depth);
    	}
    }
    
    posted @   林动  阅读(24)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 地球OL攻略 —— 某应届生求职总结
    · 周边上新:园子的第一款马克杯温暖上架
    · Open-Sora 2.0 重磅开源!
    · 提示词工程——AI应用必不可少的技术
    · .NET周刊【3月第1期 2025-03-02】
    点击右上角即可分享
    微信分享提示