《ACM国际大学生程序设计竞赛题解Ⅰ》——模拟题

  这篇文章来介绍一些模拟题,即一类按照题目要求将现实的操作转换成程序语言。

 

  zoj1003:

  On every June 1st, the Children's Day, there will be a game named "crashing balloon" on TV.   The rule is very simple.  On the ground there are 100 labeled  balloons, with the numbers 1 to 100.  After the referee shouts "Let's go!" the two players, who each starts with a score of  "1", race to crash the balloons by their feet and, at the same time, multiply their scores by the numbers written on the balloons they crash.  After a minute, the little audiences are allowed to take the remaining balloons away,  and each contestant reports his\her score, the product of the numbers on the balloons he\she's crashed.  The unofficial winner is the player who announced the highest score.

Inevitably, though, disputes arise, and so the official winner is not determined until the disputes are resolved.  The player who claims the lower score is entitled to challenge his\her opponent's score.  The player with the lower score is presumed to have told the truth, because if he\she were to lie about his\her score, he\she would surely come up with a bigger better lie.  The challenge is upheld if the player with the higher score has a score that cannot be achieved with balloons not crashed by the challenging player.  So, if the challenge is successful, the player claiming the lower score wins.

So, for example, if one player claims 343 points and the other claims 49, then clearly the first player is lying; the only way to score 343 is by crashing balloons labeled 7 and 49, and the only way to score 49 is by crashing a balloon labeled 49.  Since each of two scores requires crashing the balloon labeled 49, the one claiming 343 points is presumed to be lying.

On the other hand, if one player claims 162 points and the other claims 81, it is possible for both to be telling the truth (e.g. one crashes balloons 2, 3 and 27, while the other crashes balloon 81), so the challenge would not be upheld.

By the way, if the challenger made a mistake on calculating his/her score,  then the challenge would not be upheld.  For example, if one player claims  10001 points and the other claims 10003, then clearly none of them are telling the truth.  In this case, the challenge would not be upheld.

Unfortunately, anyone who is willing to referee a game of crashing balloon is likely to get over-excited in the hot atmosphere that  he\she could not reasonably be expected to perform the intricate calculations that refereeing requires.  Hence the need for you, sober programmer, to provide a software solution.

Input

Pairs of unequal, positive numbers, with each pair on a single line, that are claimed scores from a game of crashing balloon.

Output

Numbers, one to a line, that are the winning scores, assuming that the player with the lower score always challenges the outcome.

 

  题目大意:给出两个整数n、m(假设m>n),请你判断是否存在一种方案,使得n = f1 * f2 *... , m=F1 * F2 *...,其中对于任意的i、j,有fi≠fj,fi≠Fj,fi∈[2,100]且fj∈[2,100]。

  数理分析:其实对于题目大意的描述,笔者表述很抽象化,如果用文字描述,其实就是判断对于给出的两个整数n、m,进行因数分解(因子范围在1~100),能否得到两个完全不同的方案。假设我们已经得到了结果,我们先看看这个结果如何左右我们输出的结果。

  如果存在这样一种方案,结合原文题意,这里驳回质疑,高分胜出,即输出m、n当中较高的那个。

  如果不存在这样一种方案,则质疑成功,低分胜出,输出m、n中较小的那个。

  这里注意到原文的一段话,“By the way, if the challenger made a mistake on calculating his/her score,  then the challenge would not be upheld.  For example, if one player claims  10001 points and the other claims 10003, then clearly none of them are telling the truth.  In this case, the challenge would not be upheld.”这句话是说,如果m、n两者都没办法完成上述的因数分解,即用原文的话说是两个人都说谎,则不支持提出的质疑,按照原来的胜负态来处理,也就是高分或者获胜。

  总结起来,如果想输出较小的数,当且仅当m、n在所以的因数分解中,n能够被因数分解但是m不能。而其余的情况都是输出较大数m。

  搞清的如何输出,下面我们要解决的关键问题就是如何判断笔者在题目大意中描述的那个数学问题呢?

  其实笔者感觉这道题放在模拟题中有点“干”,它其实涉及了数论的东西和dfs的思想(关于搜索后面会有一篇文章专门介绍)。

  判断方法描述起来很简单,我们找到m、n所有的因数分解情况,然后按照给出的限制条件去判断即可。

  但是如何巧妙的变成来实现这个过程呢?要先对m、n质因分解然后排列组合么?理论上可行但似乎有些繁琐。考虑到每个因子仅能出现一次的特点,我们利用dfs进行深搜,我们首先从枚举100开始枚举2~100这99个因子,一旦发现一个m或者n的因子pm或pn(假设当前找到了m的一个因子pm),那么我们可以将问题更加的微小化。即一开始,我们当前的问题是判断整数m、n是否能够得到两种不同的因数分解方案,因子范围是2~100,那么在找到了某个因子pm之后,我们的问题便可以缩小化成如下的等价形式,判断m/pm、n是否能够得到两种不同的因数分解方案,因子范围是2~pm-1,由此我们看到这递归的程序模式,其实如果熟悉欧几里得算法的读者,会更好的理解这个过程。

  简单的参考代码如下。

 

#include<cstdio>
using namespace std;
bool atrue , btrue;

int judge(int m,int n,int p)
{
       if(atrue)   return 0;
       if(n == 1 && m == 1)
       {
            atrue = true;
            btrue = true;
            return 0;
       }
       if(n == 1) btrue = true;


       while(p > 1)
       {
            if(m%p == 0)  judge(m/p,n,p-1);
            if(n%p == 0)  judge(m,n/p,p-1);
             p--;
       }
       return 0;
}
int main()
{
      int a , b , temp;
      while(scanf("%d%d",&a,&b) != EOF)
      {
             if(b > a)
             {
                   temp = a;
                   a = b;
                   b = temp;
             }
             atrue = false;
             btrue = false;
           judge(a , b , 100);

           if(!atrue && btrue)
               printf("%d\n",b);
           else
               printf("%d\n",a);
      }
}

 

posted on 2016-06-03 10:16  在苏州的城边  阅读(1809)  评论(0编辑  收藏  举报

导航