列表

详情


NC206910. 集卡

描述

小明喜欢的游戏最近推出了一个关于游戏卡牌的活动,只有能够收集全部种类的m张游戏卡牌,就兑换最终大奖;为此小明特意去线下商店购买游戏卡包。假设你是这个商店的老板,你的店里有
n包游戏卡牌,每包里有k张游戏卡。现在你已经通过特殊手段得知每个卡包里的卡牌种类,你想知道小明是不是正的欧皇,能通过买最小数量的卡包,来赢得大奖。现在你有一个任务,就是通过已知条件算出购买卡包的最小数量是多少?

输入描述

第一行有一个整数T( 1 ≤ T ≤ 10 )表示共有T组测试样例
接下来每组的第一行有三个整数n,m,k( 1 ≤ n ≤ 100 , 1 ≤ m ≤ 17 , 1 ≤ k ≤ 17 )
n-卡包数
m-总卡牌种类数
k-卡包中的卡牌张数
接下来的n行,每行有k个整数,a1,a2 ··· ak ( 1 ≤ ai ≤ m ) 代表一个卡包中每张卡的卡牌种类。

输出描述

一个整数表示最小数量,如果小明无法集齐所有卡牌,输出-1。

示例1

输入:

2
7 8 4
1 3 5 7
2 4 6 7
8 7 6 5
4 3 2 1
8 8 8 8
2 3 5 7
1 8 8 8
1 2 1
1

输出:

2
-1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 192ms, 内存消耗: 8808K, 提交时间: 2020-06-07 13:03:34

#include <iostream>
#include <cstring>
using namespace std;
int T,n,m,k;
long long a[110],f[1<<20];
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n>>m>>k;
		memset(a,0,sizeof(a));
		memset(f,127,sizeof(f));
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=k;j++)
			{
				int x;
				cin>>x;
				a[i]=a[i] | (1<<(x-1));
			}
			f[a[i]]=1;
		}
		for(int i=1;i<=(1<<m)-1;i++)
			for(int j=1;j<=n;j++)
			{
				long long k=i|a[j];
				if(f[k]>f[i]+1) f[k]=f[i]+1;
			}
		if(f[(1<<m)-1]>100) cout<<-1<<endl;
		else cout<<f[(1<<m)-1]<<endl;
	}
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 292ms, 内存消耗: 1100K, 提交时间: 2020-06-08 20:08:52

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f;
int dp[1<<17];
int main(){
	int t;
	cin>>t;
	for(int ii=0;ii<t;ii++){
		int n,m,k;
		cin>>n>>m>>k;
		memset(dp,inf,sizeof dp);
		int flag=dp[0];
		dp[0]=0;
		for(int i=0;i<n;i++){
			int p=0;
			for(int j=0;j<k;j++){
				int x;
				cin>>x;
				p|=1<<(x-1);
			}
			for(int j=0;j<1<<m;j++){
				dp[j|p]=min(dp[j|p],dp[j]+1);
			}
		}
		if(dp[((1<<m)-1)]==flag)cout<<"-1"<<endl;
		else{
			cout<<dp[(1<<m)-1]<<endl;
		}
	}
	return 0;	
}

上一题