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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~