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 健康的好斯坦奶牛
原文:http://blog.csdn.net/finded/article/details/43063983