首页 > 代码库 > 2.1.4 Healthy Holsteins 健康的好斯坦奶牛
2.1.4 Healthy Holsteins 健康的好斯坦奶牛
2.1.4 Healthy Holsteins 健康的好斯坦奶牛
一、题目描述
农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
PROGRAM NAME: holstein
INPUT FORMAT
第1 行:一个整数V(1<=V<=25),表示需要的维他命的种类数.
第2 行:V 个整数(1<=每个数<=1000),表示牛每天需要的维他命的最小量.
第3 行:一个整数G(1<=G<=15),表示可用来喂牛的饲料的数量.下面G 行,第i 行表示编号为 i 饲料
包含的各种维他命的量的多少.
SAMPLE INPUT (file holstein.in)
4
100 200 300 400
3
50 50 50 50
200 300 200 300
900 150 389 399
OUTPUT FORMAT
输出文件只有一行,包括:
牛必需的最小的饲料种数P
后面有P 个数,表示所选择的饲料编号(按从小到大排列).
SAMPLE OUTPUT (file holstein.out)
2 1 3
二、解题思路
对于每种饲料,只有两种选择:喂或者不喂。因此我们可以对饲料进行标号(不用再标,用索引就行)。枚举所有索引的子集,即所有饲料的混合。测试每个子集是否符合要求(对应维他命数大于要求的数量),并保证子集的大小最小。
枚举子集的方法很多,可以采用DFS(位向量构造方法,元素在或不在子集中)、BFS;也可以用二进制法,枚举1 to 2^p-1的长度为p(总饲料数)的二进制来获得每个养料是否要,0表示不喂,1表示喂。这几种方法比较常用,注意简单常用的就比较好了,也马上容易写出来!
这里我是直接采用的刘汝佳的《算法竞赛入门经典》中的增量构造法代码,直接生成子集。自己要理解和写出程序不容易。
源程序
#include<iostream> #include<cstdio> using namespace std; int N,M; int v[25+5]; int vv[1000+10][1000+10]; int vis[25+5]; int temp[25]; int rst=25; int isok(int *A,int cur){ int i,j,sum; for (i=0;i<N;i++) { sum=0; for (j=0;j<cur;j++){ sum=sum+vv[A[j]][i]; } if (sum<v[i]) return 0; } return 1; } void print_subset(int n, int* A, int cur) {//求元素的子集 按(索引)字典序求解,并不是按子集长度 int i; // for(i = 0; i <cur; i++) printf("%d ", A[i]); // 打印当前索引子集集合 // printf("\n"); // if(isok(A,cur)&&cur<rst){ rst=cur; for(i = 0; i<cur+1; i++) { vis[i]=A[i]; } } int s = cur ? A[cur-1]+1 : 0; // 确定当前元素的最小可能值 for( i = s; i < n; i++) { A[cur] = i; print_subset(n, A, cur+1); // 递归构造子集 } } int main() { freopen("holstein.in","r",stdin); freopen("holstein.out","w",stdout); cin>>N; int i,j; for (i=0;i<N;i++) { cin>>v[i]; } cin>>M; for (i=0;i<M;i++) for(j=0;j<N;j++){ cin>>vv[i][j]; } print_subset(M,temp,0); cout<<rst; for (i=0;i<rst;i++) {cout<<" "<<(vis[i]+1);} cout<<endl; return 0; }
2.1.4 Healthy Holsteins 健康的好斯坦奶牛