20 分 暴力
//自己实现
//既然是暴力dfs,那就是枚举每一包糖果,如果未选,就枚举每一种口味,如果有没选的口味,就添加这一包
//dfs的参数是目前选的包数,也就是答案
//为了便于回溯,设置path数组存储当前选择的糖果序列
#include<bits/stdc++.h>
using namespace std;
const int N = 110,M = 23;
int n,m,k;
vector<int> path;
int flavor[M]; //每种糖果的口味有没有选择,已选择为1
vector<int> bao[N]; //每包里面都有k个糖果
int vis[N]; //每一包有没有选
int ans=200; //最多购买100包
void dfs(int u) //当前已选几包
{
if(u>ans) return; //剪枝
//所有口味都已经选到,这是递归的结束条件
//用path的size大小来表示是否递归结束——妙啊
if(u==n && path.size()<m) return; //选完了都不够所有糖果数
if(path.size()==m)
{
//要选择最小的,仔细一点好哇
if(u<ans) ans=u;
return;
}
for(int i=0;i<n;i++) //对每一包糖果
{
//int flag=0; //表示这一包有没有选 但是这种剪枝是错误的
if(vis[i]==0) //**这一包还没取过
{
for(int j=0;j<bao[i].size();j++) //每一种口味
{
if(flavor[bao[i][j]]==0)
{
flavor[bao[i][j]]=1; //这个口味选了
//flag==1; //这一包我们选了
path.push_back(bao[i][j]);
}
}
//if(flag==0) continue;
u++;
vis[i]=1; //这一包我选了
dfs(u);
//回溯
vis[i]=0;
u--;
for(int j=bao[i].size()-1;j>=0;j--) //每一包从后往前回溯
{
//back()?
if(path.back()==bao[i][j])
{
path.pop_back();
flavor[bao[i][j]]=0;
}
}
}
}
}
int main()
{
cin>>n>>m>>k;
for(int i=0;i<n;i++)
{
for(int j=0;j<k;j++)
{
int a;
scanf("%d",&a);
bao[i].push_back(a);
}
}
dfs(0); //初始时一包未选
if(ans==200)
{
cout<<"-1";
return 0;
}
else cout<<ans;
return 0;
}