USACO 2.1.6 Healthy Holsteins 枚举组合数

描述

农民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;
}

 









你可能感兴趣的:(USACO 2.1.6 Healthy Holsteins 枚举组合数)