其实就是简单的dfs加一个最优性剪枝,如果当前已选的大于最优解,就剪枝,思路很简单
还有一种做法就是迭代加深,每次固定要搜的深度,第一次找到解一定是最优解,因为从小到大枚举递归深度,选择饲料也是从小到大,满足字典序。
还有一点要注意,dfs枚举时不能图简单像
dfs(x+1,pos+1);
dfs(x,pos+1);
这样写,因为尽管思路明确,但是最终叠的栈帧过多会导致爆栈,所以以后应尽量避免这样的写法
dfs剪枝代码:
#include<iostream>
using namespace std;
int v,n,res=9999;
int a[300],food[200][300],select[200],ans[200];
bool check(int x)
{
for(int i=1;i<=v;i++)
{
int sum=0;
for(int j=1;j<=x;j++)
sum+=food[select[j]][i];
if(sum<a[i])return false;
}
return true;
}
void dfs(int x,int pos)
{
if(x>=res||pos>n+1)return;
if(check(x))
{
if(x<res)
{
res=x;
for(int i=1;i<=x;i++)ans[i]=select[i];
}
return;
}
for(int i=pos;i<=n;i++)
{
select[x+1]=i;
dfs(x+1,i+1);
}
}
int main()
{
cin>>v;
for(int i=1;i<=v;i++)cin>>a[i];
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=v;j++)cin>>food[i][j];
dfs(0,1);
cout<<res<<" ";
for(int i=1;i<=res;i++)cout<<ans[i]<<" ";
}
迭代加深:
#include<iostream>
using namespace std;
int v,n,res=9999;
bool flag;
int a[300],food[200][300],select[200],ans[200];
bool check(int x)
{
for(int i=1;i<=v;i++)
{
int sum=0;
for(int j=1;j<=x;j++)
sum+=food[select[j]][i];
if(sum<a[i])return false;
}
return true;
}
void dfs(int x,int pos,int maxx)
{
if(flag)return;
if(x>maxx)return;
if(check(x))
{
cout<<x<<" ";
for(int i=1;i<=x;i++)cout<<select[i]<<" ";
flag=true;
return;
}
for(int i=pos;i<=n;i++)
{
select[x+1]=i;
dfs(x+1,i+1,maxx);
}
}
int main()
{
cin>>v;
for(int i=1;i<=v;i++)cin>>a[i];
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=v;j++)cin>>food[i][j];
for(int i=1;i<=n;i++)dfs(0,1,i);
}