题目描述
糖果店的老板一共有M 种口味的糖果出售。为了方便描述,我们将M种口味编号1~M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是K颗一包整包出售。
幸好糖果包装上注明了其中K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。输入格式
第一行包含三个整数N、M 和K。
接下来N 行每行K 这整数T1,T2,...,TK,代表一包糖果的口味。
1<=N<=100,1<=M<=20,1<=K<=20,1<=Ti<=M。输出格式
一个整数表示答案。如果小明无法品尝所有口味,输出-1。
输入样例
6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2
输出样例
2
下面直接上代码:
#include <bits/stdc++.h> using namespace std; int T[25][25];//所有糖果的包包~ set<int> ss; int minn = INT_MAX; int size1; int type, cnt, bag; //type表示到目前位置的糖果种类,cnt表示回溯的糖果种类数量,bag表示目前为止的包数 int tang(int T[25][25],int N, int M, int K, int index){ if(type == M) return bag; //index到最后一个糖果包的时候返回bag糖果种类值 if(index >= N || index == 5 && type < M) return -1; //当index越出N个时,或者当遍历完所有未能找到时返回-1 for(int i = 0; i < K; i++){ size1 = ss.size(); if(ss.find(T[index][i]) == ss.end()){ ss.insert(T[index][i]); type++; cnt++; //cnt起到回溯的标记的作用后面,这里能力有限,没能想到更好的回溯方法 } } if(size1 != ss.size()) bag++; //当经过一个糖果包的时候,set里的糖果种类没有增加,则会有size1 == ss.size(), //因此当size1 != ss.size()的时候则说明set里的糖果种类增加,bag++ set<int>::iterator it; it = ss.end(); for(int i = 0; i < cnt; i++){ it--; } ss.erase(it,ss.end());//迭代器删除元素 for(int j = 1; j < N; j++) tang(T,N,M,K,index+j); cnt = 0; //cnt来回溯 return (bag == -1) ? -1 : min(minn, bag); //保存最小的bag值 } int main(){ int N,M,K; int minn = INT_MAX; cin >> N >> M >> K; for(int i = 0; i < N; i++){ for(int j = 0; j < K; j++){ cin >> T[i][j]; } } cout << tang(T, N, M, K, 0) << endl; return 0; }