P1460 健康的荷斯坦奶牛 Healthy Holsteins
P1460 健康的荷斯坦奶牛 Healthy Holsteins
题目描述
农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
输入输出格式
输入格式:第1行:一个整数V(1<=V<=25),表示需要的维他命的种类数。
第2行:V个整数(1<=每个数<=1000),表示牛每天需要的每种维他命的最小量。
第3行:一个整数G(1<=G<=15),表示可用来喂牛的饲料的种数。
下面G行,第n行表示编号为n饲料包含的各种维他命的量的多少。
输出格式:输出文件只有一行,包括
牛必需的最小的饲料种数P
后面有P个数,表示所选择的饲料编号(按从小到大排列)。
如果有多个解,输出饲料序号最小的(即字典序最小)。
输入输出样例
输入样例#1:
4 100 200 300 400 3 50 50 50 50 200 300 200 300 900 150 389 399
输出样例#1:
2 1 3
说明
USACO 2.1
翻译来自NOCOW
被卡了一个小时,第一次写剪纸的蒟蒻就是我。
首先就是要枚举不重复的子集,根据测算,只需要枚举25 +24 +23 +...+1 = (25 + 1)*25/2个子集,所以时间复杂度是相当低的。
但是如果枚举成25!的子集,一定会崩掉。
我们为了避免枚举重复的子集,采取了这样的枚举自己方法(紫书里还有一种):
枚举子集内元素个数1..n,并保证子集是单调递增的。这样就能够补充不漏的枚举子集。
上代码。
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> const int MAXN = 25 + 15; const int MAXM = 15 + 15; int n; int min[MAXN]; int m; int value[MAXM][MAXN]; int c[MAXN]; int num[MAXN]; bool b[MAXM]; bool IsFull[MAXN]; int ans; int cnt; bool ok; void dfs(int step,int pre) { if(ok)return; if(step > cnt + 1) return; if(step == cnt + 1) { for(int i = 1;i <= n;i ++) { int sum = 0; for(int j = 1;j <= cnt;j ++) { sum += value[num[j]][i]; } if(sum < min[i])return; } ans = cnt; ok = true; return; } for(int i = 1;i <= m;i ++) { if(ok)return; if(i <= pre)continue; if(!b[i]) { num[step] = i; b[i] = true; dfs(step + 1,i); b[i] = false; } } } int main() { freopen("data.txt", "r", stdin); ans = 99999999; scanf("%d", &n); for(int i = 1;i <= n;i ++) { scanf("%d", &min[i]); } scanf("%d", &m); for(int i = 1;i <= m;i ++) { for(int j = 1;j <= n;j ++) { scanf("%d", &value[i][j]); } } for(int i = 1;i <= m;i ++) { cnt ++; dfs(1,0); if(ok) break; } printf("%d ", ans); for(int i = 1;i <= ans;i ++) { printf("%d ", num[i]); } return 0; }