C++ 信息学奥赛 奶牛喂养问题

题目描述

农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。

给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。

维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。

输入格式

从文件cow.in中读取数据。

1行:一个整数V(1<=V<=25),表示需要的维他命的种类数。

2行:V个整数(1<=每个数<=1000),表示牛每天需要的每种维他命的最小量。

3行:一个整数G(1<=G<=15),表示可用来喂牛的饲料的种数。

下面G行,第n行表示编号为n饲料包含的各种维他命的量的多少。

输出格式

输出到文件cow.out中去。

输出只有一行,包括牛必需的最小的饲料种数P

后面有P个数,表示所选择的饲料编号(按从小到大排列)。

如果有多个解,输出饲料序号最小的(即字典序最小)。

样例输入

4

100 200 300 400

3

50  50  50  50

200 300 200 300

900 150 389 399

样例输出

2 1 3

复制代码
  1 #include <iostream>
  2 using namespace std;
  3 
  4 int V,G;
  5 int vneed[25] = {0};    // 每种维他命所需的量
  6 int ghave[15][25] = {0};    // 提供的饲料情况
  7 
  8 // listTemp存储样式:       下标0              下标1        下标2    ...
  9 // 对应存储的东西:    [本方案需要的饲料种类数][饲料编号1][饲料编号2]...
 10 int listTemp[200010][26] = {0};    // 用于暂存选取方案,注意行数要足够多
 11 
 12 int indexFlag = 0;    // 用于记录listTemp被使用到了哪一行
 13 
 14 // 最终结果
 15 int result[26] = {0};
 16 
 17 /*
 18 判断listTemp中下标为listIndex的方案是否满足需求
 19 listIndex listTemp下标
 20 满足返回true
 21 不满足返回false
 22 */
 23 bool isEnough(int listIndex)
 24 {
 25     // 存储方案中的各维他命进行累加的结果
 26     int vsum[25] = {0};
 27     
 28     // 方案中的饲料种类数
 29     int num = listTemp[listIndex][0];
 30     
 31     // 遍历所有的饲料,此处是从listTemp[listIndex]中获取的饲料编号,i为listTemp[listIndex]的下标,应从1开始
 32     for(int i=1;i<=num;i++)    
 33     {
 34         // ghaveIndex代表所取出来的饲料的编号
 35         int ghaveIndex = listTemp[listIndex][i];    
 36         for(int j=0;j<V;j++)    // 遍历维他命并累加
 37         {
 38             vsum[j] += ghave[ghaveIndex][j];
 39         }
 40     }
 41     // 进行判断
 42     for(int i=0;i<V;i++)
 43     {    
 44         // 有一种元素不足则直接返回false
 45         if(vsum[i] < vneed[i]) return false;
 46     }
 47     // 上面没return意味着满足条件
 48     return true;
 49 }
 50 
 51 /*
 52 跟踪测试用,用于检查每次往listTemp中存放的方案是否正确
 53 */
 54 void show(int listIndex)
 55 {
 56     cout << "----- show test -----\n";
 57     cout << "listIndex: " << listIndex << endl;
 58     int needNum = listTemp[listIndex][0];
 59     cout << needNum << " ";
 60     for(int i=1;i<=needNum;i++)
 61     {
 62         cout << listTemp[listIndex][i] << " ";
 63     }
 64     cout << endl;
 65     cout << "----- end show  -----\n";
 66 }
 67 
 68 /*
 69 listIndex 饲料方案在listTemp中的索引号,会作为继续搜索的方案头用
 70 last 最后被加入到方案中的饲料编号,便于继续往下加饲料
 71 */
 72 void bfs(int listIndex,int last)
 73 {
 74     // 判断传入的方案是否满足需求
 75     if(isEnough(listIndex))
 76     {
 77         // 满足需求应和暂存的结果方案进行比较
 78         if(listTemp[listIndex][0] < result[0])
 79         {
 80             // 更优方案,重置并复制内存
 81             memset(result, 0, sizeof(result));
 82             memcpy(result, listTemp[listIndex], (listTemp[listIndex][0]+1)*sizeof(int));
 83         }
 84     }else    // 还不满足,继续加饲料
 85     {
 86         // 遍历后续饲料种类,逐一添加进方案
 87         for(int i=last+1;i<G;i++)
 88         {
 89             // 以listIndex的方案为头部,新建一个方案到indexFlag新内存空间中
 90             memcpy(listTemp[indexFlag], listTemp[listIndex], (listTemp[listIndex][0]+1)*sizeof(int));
 91             // 在方案中加入新的饲料,newIn用于测定应该将饲料编号放在哪个位置
 92             int newIn = listTemp[indexFlag][0]+1;
 93             listTemp[indexFlag][newIn] = i;
 94             // 更新本方案所包含的饲料种类数
 95             listTemp[indexFlag][0] = listTemp[indexFlag][0] + 1;
 96             // indexFlag标记更新
 97             indexFlag++;
 98             // 调用bfs
 99             bfs(indexFlag-1, i);
100         }
101     }
102 }
103 
104 int main()
105 {
106     // 结果0位置标记为999便于方案比较过程中的替换
107     result[0] = 999;
108     
109     // 题目所提供的其他数据的测试
110     // freopen("./data/cow/cow10.in","r",stdin);
111     
112     // 数据的读入
113     cin >> V;
114     for(int i=0;i<V;i++)
115         cin >> vneed[i];
116     cin >> G;
117     for(int i=0;i<G;i++)
118     {
119         for(int j=0;j<V;j++)
120             cin >> ghave[i][j];
121     }
122     
123     // 每次只拿一种饲料,然后开始测试
124     for(int i=0;i<G;i++)
125     {
126         // 将编号为i的饲料放入indexFlag下标中,注意0位置为数量,1位置开始放饲料编号
127         listTemp[indexFlag][0] = 1;
128         listTemp[indexFlag][1] = i;
129         // indexFlag注意自增
130         indexFlag++;
131         // 按照我们的bfs函数定义,传入的第一个参数是当前刚刚被建立的方案所存放的下标,所以应-1
132         // 同时传入i饲料编号,是为了bfs继续向前添加饲料
133         bfs(indexFlag-1, i);
134     }
135     
136     // 输出结果
137     int needNum = result[0];
138     cout << needNum << " ";
139     for(int i=1;i<=needNum;i++)
140         cout << result[i]+1 << " ";
141     cout << endl;
142             
143     return 0;
144 }
复制代码

 

posted @   我信你个鬼!  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示