农民 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;
}