描述
农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
格式
PROGRAM NAME: holstein
INPUT FORMAT:(file holstein.in)
第1行:一个整数V(1<=V<=25),表示需要的维他命的种类数。
第2行:V个整数(1<=每个数<=1000),表示牛每天需要的每种维他命的最小量。
第3行:一个整数G(1<=G<=15),表示可用来喂牛的饲料的种数。
下面G行,第n行表示编号为n饲料包含的各种维他命的量的多少。
OUTPUT FORMAT:(file holstein.out)
输出文件只有一行,包括
牛必需的最小的饲料种数P
后面有P个数,表示所选择的饲料编号(按从小到大排列)。
如果有多个解,输出饲料序号最小的(即字典序最小)。
SAMPLE INPUT
4 100 200 300 400 3 50 50 50 50 200 300 200 300 900 150 389 399
SAMPLE OUTPUT
2 1 3
分析:
这个题目是找一个最优方案,由于数据比较小,直接枚举是直接可以过掉的,但是在枚举的实现上有两种思路。
第一种是按照乘法原理的思路,一共15种药,每一种要么选择,要么不选择,所以一共枚举次数的计算表达式为 2^15 这么多种。
第二种是按照组合原理的思路,一共15种药物,我分15次逐层深入遍历,需要的枚举次数最多为 C(15,1)+C(15,2).。。。+C(15,15).其值和2^15是一样的。
这两种方法都能通过代码实现,而且很容易,但是在效率上有比较大的区别,打个比方,假设一共只有三种药物,
那么按照第一种思路,枚举顺序为 001,010,011,100,101,110,111 (0,代表不选择,1代表选择,比如001即表示,只选择第三种药物)
按照第二种思路 ,枚举序列为 1,2,3,12,13,23,123 (可以发现1,2,3,属于C(3,1),12,13,23 属于C(3,2),123则属于C(3,3))
如果说那种思路好的话,那么根据这道题目的具体情况,肯定是第二种要好,因为本题对输出上有要求“如果有多个解,输出饲料序号最小的(即字典序最小)。”,可以发现第二种是正好按照题目要求的顺序来的,第一种思路的输出虽然也是“字典序”,但是他不符合“药物总数”从小达到大的输出要求,比如011在100前面,但是011表示两种药物,100表示一种药物。
我的代码是第二种思路,逐层生成组合序列,虽然每一层用的是DFS,但是整体上有点BSF的特点,因为只要找到就输出。后面的曾就不用搜索了。
#include <iostream> #include<vector> #include<fstream> #include<cstring> #include<ctime> using namespace std; ifstream infile; ofstream outfile; const int S = 16; int p[S]; int V,G; int vit[26]; int drag[S][26]; void dfs(int,int); bool isFind = false; bool calc(int); int main(){ infile.open("holstein.in"); outfile.open("holstein.out"); //cin>>V; infile>>V; for(int i=1;i<=V;i++) infile>>vit[i]; infile>>G; for(int i=1;i<=G;i++) for(int j=1;j<=V;j++) infile>>drag[i][j]; for(int i=1;i<=G;i++){ if(isFind) break; dfs(1,i); } return 0; } void dfs(int cur,int step){ if(isFind) return; if(cur>step){/* */ if(calc(step)){ outfile<<step<<" "<<p[1]; for(int i=2;i<=step;i++) outfile<<" "<<p[i]; outfile<<endl; isFind = true; } return; } for(int i = p[cur-1]+1;i<=G;i++){ p[cur] = i; dfs(cur+1,step); } } bool calc(int step){ for(int i=1;i<=V;i++){ int sum = 0; for(int j=1;j<=step;j++) sum+=drag[p[j]][i]; if(sum<vit[i]) return false; } return true; }