题意:农民JOHN以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
输出:
输出文件只有一行,包括
牛必需的最小的饲料种数P
后面有P个数,表示所选择的饲料编号(按从小到大排列)。
如果有多个解,输出饲料序号最小的(即字典序最小)。
分析:总共有十五种饲料,要找出符合能满足条件的最少的种数,相当于要求出一种组合,那么就求出各种长度的组合,再找出符合条件的最小字典序。
用BFS做的,关键是记录状态,每一个状态要记录几个量
struct node
{
int state;//用位来记录路径,即使用过哪几种饲料
int ver[26];//保存状态值,
short cur;//当前选择的编号最大的饲料
short cnt;//已选择的种类数
};
每次取出一种状态时,从当前最大饲料的编号之后开始添加选择的饲料,同时记录下所选择的饲料编号,这样,第一个满足条件就题目所求的。
以 测试例子为例:
整个搜索过程是这样的:
先将这三个状态压入对列 (1) (2) (3)
取出(1)之后,就会分别将(1, 2) (1,3)
取出(2) 之后,就会将(2,3)
取出(3) 之后……
取出(1,2)之后,就会将(1,2,3)
取出(1,3)之后,满足条件,退出;
之后输出就比较简单了;
/* ID: nanke691 LANG: C++ TASK: holstein */ #include<iostream> #include<fstream> #include<string.h> #include<queue> #include<algorithm> using namespace std; struct node { int state;//用位来记录路径,即使用过哪几种饲料 int ver[26];//保存状态值, short cur;//当前选择的编号最大的饲料 short cnt;//已选择的种类数 }; int hol[20][30]; int V,G,aim[30],len,ans; queue<node> Q; bool compare(int *a)//判断是否符合条件 { for(int i=1;i<=V;i++) if(a[i]<aim[i]) return false; return true; } void BFS() { node s,f; for(int i=1;i<=G;i++) { for(int j=1;j<=V;j++) s.ver[j]=hol[i][j]; s.state=(1<<(i-1)); s.cur=i; s.cnt=1; Q.push(s); } len=100000000; while(!Q.empty()) { f=Q.front(); Q.pop(); if(f.cnt<=len && compare(f.ver)) { len=f.cnt; ans=f.state; break; } for(int i=f.cur+1;i<=G;i++) { for(int j=1;j<=V;j++) s.ver[j]=f.ver[j]+hol[i][j]; s.cnt=f.cnt+1; s.cur=i; s.state=(f.state | (1<<(i-1)));//记录下当前选取的编号 Q.push(s); } } } int main() { freopen("holstein.in","r",stdin); freopen("holstein.out","w",stdout); scanf("%d",&V); for(int i=1;i<=V;i++) scanf("%d",&aim[i]); scanf("%d",&G); for(int i=1;i<=G;i++) for(int j=1;j<=V;j++) scanf("%d",&hol[i][j]); BFS(); cout<<len<<' '; int flag=0; for(int i=1;i<=G;i++) { if((ans &(1<<(i-1)))!=0) { if(!flag) cout<<i,flag=1; else cout<<' '<<i; } } cout<<endl; }