usaco section 2.1 健康的荷斯坦奶牛 dfs剪枝——迭代加深

其实就是简单的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);
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值