zoukankan      html  css  js  c++  java
  • 生日蛋糕

    题面:https://www.luogu.org/problemnew/show/P1731

    剪枝:

    可行性剪枝:

    1.为了保证严格大于,并且是整数,所以每一层的h,r最小是m-now+1

    2.如果最后都选择能选的最大的,比n还小,return

    3.如果最后都选择能选的最小的(这个可以预处理),比n还大,return

    最优性剪枝:

    1.如果S>ans,return

    2.如果最后都选择表面积最小的(这个可以预处理),比ans还大return

    公式可以手动推。

    顺序:
    1.倒序能比较快的达到上界。(正序会TLE)

    剪枝还是比较好想的。

    (但是第一遍全想到了,但是没有写全)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=20000+5;
    const ll inf=(1LL*1<<61);
    int n,m;
    ll ans=inf;
    int sz[20],biao[20];
    bool che(int now,ll S,ll V,ll r,ll h){
        ll msz=V+sz[m-now+1];
        if(msz>n) return false;
        
        ll mib=S+biao[m-now+1];
        if(mib>ans) return false;
        
        ll mxz=V;
        h--,r--;
        for(int i=now;i<=m;i++){
            mxz+=h*r*r;
            h--,r--;
        }
        if(mxz<n) return false;
        return true;
    }
    void dfs(int now,ll S,ll V,ll r,ll h){
        
        if(S>=ans) return;
        if(!che(now,S,V,r,h)) return;
        //cout<<now<<" : "<<S<<" "<<V<<" las "<<r<<" and "<<h<<endl;
        //if(r==-1||h==-1) return;
        if(now==m+1){
            if(V==n){
                ans=min(ans,S);
            }
            return;    
        }
        if(now==1){
            for(ll i=sqrt(n);i>=m;i--){
                for(ll j=n/(i*i);j>=m;j--){
                    //if(!che(now+1,i*i+2*i*j,j*i*i))break;
                    dfs(now+1,i*i+2*i*j,j*i*i,i,j);
                }
            }        
        }
        else if(now<m){
            for(ll i=r-1;i>=m-now+1;i--){
                for(ll j=h-1;j>=m-now+1;j--){
                    //if(!che(now+1,S+2*i*j,V+i*i*j)) break;
                    dfs(now+1,S+2*i*j,V+i*i*j,i,j);
                }
            }
        }
        else if(now==m){
            int re=n-V;
            if(re<0) return;
            for(ll i=r-1;i>=m-now+1;i--){
                if(re/(i*i)>=h) break;
                if(re%(i*i)==0){
                    if(re/(i*i)<h){
                        int hh=re/(i*i);
                        dfs(now+1,S+2*hh*i,n,i,hh);
                    }
                }
            }
        }
    }
    int main(){
        ans=inf;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            sz[i]=sz[i-1]+i*i*i;
            biao[i]=biao[i-1]+2*i*i;
        }
        dfs(1,0,0,n+1,n+1);
        printf("%lld",ans==inf?0:ans);return 0;
    }
  • 相关阅读:
    方法的调用
    控制语句
    运算符 及 流程控制语句
    标识符 二进制 数据类型之间的转换
    大数据中java基础概述
    Java常见对象
    Java为什么要在虚拟机中运行
    java基础之反射机制
    多线程
    Ajax详解
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9780025.html
Copyright © 2011-2022 走看看