P1460 [USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins

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

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

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

输入格式

第一行一个整数 vv,表示需要的维他命的种类数。
第二行 vv 个整数,表示牛每天需要的每种维他命的最小量。

第三行一个整数 gg,表示可用来喂牛的饲料的种数。
下面 gg 行,第 nn 行表示编号为 nn 饲料包含的各种维他命的量的多少。

输出格式

输出文件只有一行,包括牛必需的最小的饲料种数 pp;后面有 pp 个数,表示所选择的饲料编号(按从小到大排列)。

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

输入输出样例

输入 #1复制

4
100 200 300 400
3
50  50  50  50
200 300 200 300
900 150 389 399

输出 #1复制

2 1 3

思路:每次递归记录当前搜到的牛和已经选的组数

对每个牛有选和不选两种情况

用一个sum数组来记录所选的每种饲料的总数

每次选的时候sum加上当前饲料的v种饲料,记录一下选的方案

最后当饲料搜完的时候看看满足不满足对于所有饲料sum都大于等于要求最小值

如果满足且组数小于当前最优解,那么更新组数和方案


/*

 .----------------.  .----------------.  .----------------.  .----------------. 
| .--------------. || .--------------. || .--------------. || .--------------. |
| |  ________    | || |  _________   | || | ____    ____ | || |     ____     | |
| | |_   ___ `.  | || | |_   ___  |  | || ||_   \  /   _|| || |   .'    `.   | |
| |   | |   `. \ | || |   | |_  \_|  | || |  |   \/   |  | || |  /  .--.  \  | |
| |   | |    | | | || |   |  _|  _   | || |  | |\  /| |  | || |  | |    | |  | |
| |  _| |___.' / | || |  _| |___/ |  | || | _| |_\/_| |_ | || |  \  `--'  /  | |
| | |________.'  | || | |_________|  | || ||_____||_____|| || |   `.____.'   | |
| |              | || |              | || |              | || |              | |
| '--------------' || '--------------' || '--------------' || '--------------' |
 '----------------'  '----------------'  '----------------'  '----------------'

*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<cmath>
#include<stack>
#define int long long
#define lowbit(x) x&(-x)
#define PI 3.1415926535
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b) {
	return b? gcd(b,a%b):a;
}
/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/
//int e[N],ne[N],h[N],idx,w[N];
/*void add(int a,int b,int c){
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}
*/
const int N=25+10;
int v,g;
int minv[N];
int c[N][N];
int path[N];//记录方案
int sum[N];
int ans;
int op[N];//记录每次递归选的组数
void dfs(int u,int k){//记录当前牛的编号和已经选了几组
	if(k>ans)return ;//优化剪枝,如果当前组数大于已经搜出来的最优解那么就剪
	if(u==g){//如果搜完了所有牛
		bool f=true;//判断是不是满足营养够的条件
		for(int i=0;i<v;i++){
			if(sum[i]<minv[i]){
				f=false;
				break;
			}
		}
		if(f&&ans>k){//如果满足条件而且组数小于最优解就更新(在这注意一下,我们每次更新的条件是组数小于最优解,因为当等于的时候肯定是前面已经搜到的方案是最小的字典序
			ans=k;
			for(int i=0;i<ans;i++)path[i]=op[i];
		}
		return ;
	}
	for(int i=0;i<v;i++)sum[i]+=c[u][i];
	op[k]=u;
	dfs(u+1,k+1);
	for(int i=0;i<v;i++)sum[i]-=c[u][i];
	op[k]=0;
	dfs(u+1,k);	
}
void sove(){
	cin>>v;
	for(int i=0;i<v;i++){
		cin>>minv[i];
	}
	cin>>g;
	for(int i=0;i<g;i++){
		for(int j=0;j<v;j++){
			cin>>c[i][j];
		}
	}
	ans=g+1;//这里注意初始化ans=g+1,因为当全选的时候就到不了ans>k,那么就不能更新path
	dfs(0,0);
	cout<<ans<<" ";
	for(int i=0;i<ans;i++)cout<<path[i]+1<<" ";
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie() ,cout.tie() ;
	int t=1;
//	cin>>t;
	while(t--){
		sove();
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值