hdu 4574 Bombs (dfs+剪枝)

这篇博客详细介绍了如何解决HDU 4574 Bombs的问题,主要利用深度优先搜索(DFS)结合剪枝策略来优化求解过程。博主分享了具体的算法实现思路和关键代码片段,帮助读者理解在解决此类问题时如何有效地避免无效搜索,提高解题效率。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

Bombs

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 326    Accepted Submission(s): 45


Problem Description
  Terrorists are around everywhere, they always make troubles by detonating bombs. The terrorist have some gunpowder to make bombs, different gunpowder has different damage, every kind of gunpowder can use any times, and the power of one bomb is the product of the gunpowder it consists of. Let’s see how they make a bomb.
  At the beginning they decide to use X parts of gunpowder to make a bomb, and then choose X parts of gunpowder, every time the damage of the gunpowder they choose can’t be smaller than the last time they choose excepting the first time. After choosing X parts gunpowder terrorists get gunpowder[1], gunpowder[2] ... gunpowder[X] ( gunpowder[1] <= gunpowder[2] <= ... <= gunpowder[X]), and then mix the X parts gunpowder to generate a bomb with power of the product of the damage of the gunpowder. Terrorists make bombs in some order, if they make bomb_A before bomb_B one of the following conditions should meet.
(1)Terrorists use less parts gunpowder to make bomb_A than bomb_B.
(2)Terrorists both use X parts of gunpowders to make bomb_A and bomb_B. There exist an integer j(j <=X),for all i < j,gunpowder_A[i] = gunpowder_B[i] and gunpowder_A[j] < gunpowder_B[j].
  Now, the police get the gunpowder by some way, police find that the gunpowder’s damage is in the range of A to B(A, B included), police want to know the K-th bomb with the power in the range of L to R(L, R included).
 

Input
  There are multiple cases, the first line is an integer T denoting the number of the case, for each case has five integers A, B, L, R, K in a line. A, B denote the damage range of the gunpowder. L, R denote the power range of the bomb, K denotes the K-th bomb with the power in the range L to R that police want to know.
2<=A <= B<=10^6
1<=L<=R<=10^9
1<=K<=10^6
 

Output
  For each case output in the format in the first line “Case #x: y” x is the case number start from 1, y is the power of the bomb, and the second line with the gunpowder in the order they choose. If there is no more than K bombs in the range of L to R just output one line “Case #x: -1”.
 

Sample Input
  
4 2 2 1 4 1 2 5 1 4 4 73 23642 12 20903 29401 2 50 1 1000000000 815180
 

Sample Output
  
Case #1: 2 2 Case #2: 4 2 2 Case #3: -1 Case #4: 59200 4 4 5 20 37
Hint
In the second case we have 4 kinds of gunpowder with damage 2, 3, 4, 5. the first bomb is “2”with power of 2 The second bomb is “3” with power of 3 The third bomb is “4” with power of 4 The fouth bomb is “5” with power of 5 The fifth bomb is “2 2” with power of 2 * 2 = 4 So the 4-th bomb with power in the range of 1 to 4 is “2 2”.
 

Source

题意:
给一个区间[A,B],表示有B - A + 1种火药,火药i的威力值为i,现在要用这些火药做炸弹,每次先按原料个数再按原料的字典序做炸弹。每个炸弹的威力值是每种原料威力值的乘积。现在给一个区间[L,R]表示炸弹的威力值范围,求第K个炸弹的配方。

思路:因为炸弹的威力值是原料威力值的乘积,R不超过10^9,A至少为2,所以极端情况下炸弹至少要29种原料,所以直接搜就可以了。

剪枝:当搜到第i中火药的时候,假设剩下的全部用威力值最大的B种火药,如果还不能达到炸弹威力值下界L,退出;假设剩下的全部用威力值最小的A种火药,已经超过炸弹威力值上界R,退出。加了这个剪枝还是TLE呀,搜到倒数第二层的时候统计个数就险过了。

ps:开始想的以为是对的剪枝错了,所以想剪枝时一定要合理。


代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 35
using namespace std;

int n,m,ans,depth,flag;
long long s[maxn];
long long a,b,l,r,k,temp,cnt;
long long dl,dr,tl,tr;

long long pow(int cc,int num)  // 计算cc^num
{
    int i;
    if(num==0) return 1;
    long long ppt=cc;
    for(i=1;i<num;i++)
    {
        ppt*=cc;
    }
    return ppt;
}
void dfs(int p,int pos,long long val)
{
    if(flag) return ;
    int i,j;
    long long le,ri;
    if(pos==depth)                // 对倒数第二层处理
    {
        long long rrr=r/val;
        long long lll=l/val;
        if(l%val!=0) lll++;       // 注意'/'会取下界 要处理掉
        if(rrr>b) rrr=b;          // 注意和边界比较
        if(lll<p) lll=p;
        if(rrr>=lll&&cnt+rrr-lll+1<k)
        {
            cnt+=(rrr-lll+1);
            return ;
        }
        else if(rrr<lll) return ;
    }
    if(pos==depth+1)
    {
        if(val>=l&&val<=r) cnt++;
        if(cnt==k)
        {
            flag=1;
            printf("%I64d\n",val);
            for(i=1;i<depth;i++)
            {
                printf("%I64d ",s[i]);
            }
            printf("%I64d\n",s[i]);
        }
        return ;
    }
    le=(long long)(l/(val*pow(b,depth-pos)));
    ri=(long long)(r/(val*pow(a,depth-pos)))+1;
    if(le<p) le=p;
    if(ri>tr) ri=tr;
    for(i=le;i<=ri;i++)
    {
        s[pos]=i;
        if(val*i*pow(i,depth-pos)>r) return ;
        dfs(i,pos+1,val*i);
    }
}
int main()
{
    int i,j,t,test=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&l,&r,&k);
        cnt=min(b,r)-max(a,l)+1;
        printf("Case #%d: ",++test);
        if(r<a)
        {
            printf("-1\n");
            continue ;
        }
        if(cnt>=k)
        {
            long long tmd=a>l?a:l;       // 特判一定要注意a、l的大小!
            printf("%I64d\n%I64d\n",tmd+k-1,tmd+k-1);
            continue ;
        }
        if(cnt<0) cnt=0;
        flag=0;
        dl=dr=2;           // 计算上下深度
        temp=b*b;
        while(temp<l)
        {
            dl++;
            temp*=b;
        }
        temp=a*a;
        while(temp<=r)
        {
            dr++;
            temp*=a;
        }
        for(i=dl;i<dr;i++)
        {
            depth=i;
            tl=(long long)(l*1.0/pow(b,i-1));
            if(tl<a) tl=a;
            tr=(long long)(r*1.0/pow(a,i-1))+1;
            if(tr>b) tr=b;
            for(j=tl;j<=tr;j++)
            {
                s[1]=j;
                if(j*pow(j,i-1)>r) break ;
                dfs(j,2,j);
                if(flag) break ;
            }
            if(flag) break ;
        }
        if(!flag) printf("-1\n");
    }
    return 0;
}


 

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值