HDU5610——暴力枚举(可减少遍历次数)

题目描述:

Baby Ming and Weight lifting

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 827    Accepted Submission(s): 318


Problem Description
Baby Ming is fond of weight lifting. He has a barbell pole(the weight of which can be ignored) and two different kinds of barbell disks(the weight of which are respectively  a  and  b ), the amount of each one being infinite.

Baby Ming prepare to use this two kinds of barbell disks to make up a new one weighted  C (the barbell must be balanced), he want to know how to do it.

 

Input
In the first line contains a single positive integer  T , indicating number of test case.

For each test case:

There are three positive integer  a,b , and  C .

1T1000,0<a,b,C1000,ab
 

Output
For each test case, if the barbell weighted  C  can’t be made up, print Impossible.

Otherwise, print two numbers to indicating the numbers of  a  and  b  barbell disks are needed. (If there are more than one answer, print the answer with minimum  a+b )
 

Sample Input
  
  
2 1 2 6 1 4 5
 

Sample Output
  
  
2 2 Impossible

题目链接

题意:

有一个杠铃杆(重量忽略),和2种类型的杠铃片(重量分别为a和b),每种杠铃片都有无限个。
打算用这2种杠铃片组成重量为C的杠铃(杠铃必须平衡),他想让你告诉他,应该如何组合

输入一个正整数T(1≤T≤1000)表示测试组数
每组测试数据输入3个正整数a,b,C(0<a,b,C≤1000), 表示2种杠铃片的重量,以及杠铃的重量。

如果不能够组成重量为C的杠铃,输出Impossible。
否则输出2个数,表示需要a杠铃片的数量,和b杠铃片的数量。(如果有多种答案,输出a+b最小的方案)

解析:

这道题属于简单题,由于杠铃的杠铃片要成双,并且杠铃必须平衡,所以一开始我们的想法就是直接枚举即可

完整代码实现:

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int T;
    int a,b,C;
    while(scanf("%d",&T) == 1)
    {
        while(T--)
        {
            scanf("%d %d %d",&a,&b,&C);
            if(C % 2 != 0)
                printf("Impossible\n");
            else
            {
                if(a < b)
                {
                    bool tmp = false;
                    for(int i = 0; i <= 1000; i++)
                    {
                        for(int j = 0; j <= 1000; j++)
                        {
                            if(i*a+j*b == C/2)
                            {
                                printf("%d %d\n",2*i,2*j);
                                tmp = true;
                                break;
                            }
                        }
                        if(tmp)  break;
                    }
                    if(!tmp)     printf("Impossible\n");
                }
                else
                {
                    bool tmp = false;
                    for(int i = 0; i <= 1000; i++)
                    {
                        for(int j = 0; j <= 1000; j++)
                        {
                            if(i*b+j*a == C/2)
                            {
                                printf("%d %d\n",2*j,2*i);
                                tmp = true;
                                break;
                            }
                        }
                        if(tmp)  break;
                    }
                    if(!tmp)     printf("Impossible\n");
                }
            }

        }

    }
    return 0;
}
于是我们很快得到了这样的答案:


但是这样是否是我们满意的答案呢?明显不是的,在我们双重for循环暴力遍历的时候,很明显,存在很多不必要的遍历操作,如果不存在这样的a和b的组合的话,就要遍历1000*1000次,可想而知,效率是多么的底下,所以在内层和外层循环中,我们可以做一些判断,从而减少遍历的次数

内层循环中,是判断i,j两个值是否满足表达式,所以当遍历到i*a+j*b > c的情况时,由于是升序遍历,那么内层循环中后来的情况均不满足,因此可跳出内层循环。同样,在外层循环中也可设置类似条件,跳出循环从而减少遍历次数,提高程序效率。因此我们得出优化后的代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int T;
    int a,b,C;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d",&a,&b,&C);
        if(C % 2 != 0)
            printf("Impossible\n");
        else
        {
            int c = C / 2;
            bool tmp = false,flag = false;
            if(a < b)
            {
                for(int i = 0; i <= 1000; i++)
                {
                    if(tmp)  break;
                    else if(i*a>c)   break;
                    for(int j = 0; j <= 1000; j++)
                    {
                        if(i*a+j*b == c)
                        {
                            printf("%d %d\n",2*i,2*j);
                            tmp = true;
                            break;
                        }
                        else if(i*a+j*b > c)     //类似于剪枝的思想,减少遍历次数
                            break;
                    }
                }
                if(!tmp)     printf("Impossible\n");
            }
            else
            {
                for(int i = 0; i <= 1000; i++)
                {
                    if(tmp)  break;
                    else if(i*b>c)   break;
                    for(int j = 0; j <= 1000; j++)
                    {
                        if(i*b+j*a == c)
                        {
                            printf("%d %d\n",2*j,2*i);
                            tmp = true;
                            break;
                        }
                        else if(i*b+j*a > c)   //类似于剪枝的思想,减少遍历次数
                            break;
                    }
                }
                if(!tmp)     printf("Impossible\n");
            }
        }
    }
    return 0;
}
很快,结果便出来了:



体会:在不改变可读性以及程序的正确性的情况下,自己应该有意识地优化自己的代码,这样的话才能使得自己的程序效率更高,而更加优雅。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值