【codevs1005】生日礼物

这个题直接爆搜显然很好想,但是直接爆搜而不剪枝的话最坏复杂度应该是6^10*10,显然会爆炸。开始我并没有想到怎么剪枝,因此只拿了80,看过题解后恍然大悟:我们可以提前处理好第i种本子之后所有的本子每种纸最多还能用多少,搜索的时候,如果发现某种颜色的纸,就算之后所有的该种颜色的纸全部用上都无法超越现在的最大值,则退出

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline void re(int &a)
{
    a=-0;
    char b=getchar();
    while(b<'0'||b>'9')
        b=getchar();
    while(b>='0'&&b<='9')
        a=a*10+b-'0',b=getchar();
}
int n,m,s[20],ben,sum[12][12],a[12][12],bi[12],cun[20],ans=1000;
void dfs(int tot,int ceng)//tot记录买了多少个本子,ceng记录现在判断到第几种本子了 
{
    bool flag=0;
    for(int i=2;i<=m;i++)
    {
        if(s[i]==0||s[i]!=s[i-1]||s[i]>ans||s[i-1]>ans)
        {
            flag=1;break;
        }
    }
    if(flag==0)
    {
        ans=min(ans,s[1]);return;
    }
    if(tot==ben||ceng==n)
        return;
    int mx=0;
    for(int i=1;i<=m;i++)
        mx=max(mx,s[i]);
    for(int i=1;i<=m;i++)//如果我们发现,就算把下面的所有本子都买了,也不能追上现在的最大值,直接停止 
    {
        if(mx>s[i]+sum[ceng+1][i])
            return;
    }
    for(int i=0;i<=bi[ceng+1];i++)//枚举这种本子买几个 
    {
        for(int j=1;j<=m;j++)
            s[j]+=a[ceng+1][j]*i;
        cun[ceng+1]=i;
        dfs(tot+i,ceng+1);
        for(int j=1;j<=m;j++)
            s[j]-=a[ceng+1][j]*i;
        cun[ceng+1]=0;
    }
}
int main()
{
    re(n),re(m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            re(a[i][j]);
    for(int i=1;i<=n;i++)
        re(bi[i]),ben+=bi[i];    
    for(int i=n;i>=1;i--)//我们可以通过提前算出每种本子下面每种纸还有多少可以用的,以此来帮助剪枝 
        for(int j=m;j>=1;j--)
            sum[i][j]=sum[i+1][j]+a[i][j]*bi[i];
    dfs(0,0);
    if(ans*m<=1000)
        cout<<ans*m;
    else
        cout<<"alternative!";
}

 

posted @ 2017-11-03 21:01  那一抹落日的橙  阅读(186)  评论(0编辑  收藏  举报