博得一笑

编程只为博得一笑

所有的代码都自己敲……
    所有的BUG都自己找……
 

博得写的博客

写博客的博得
2005自制游戏《小鱼蛋与小仙女》 下载  Hot      学思湖怪超COOL文字生成器II黄金特别版——华丽登场!!!  New Cool Hot
     写程序看来是我破解无聊的最好的解药……

    早晨突然发现前些日子,某个酒足饭饱的午后,黄哥问的一个傻问题——当时也没有听清楚——居然是一道编程题!而且是很有难度的一道,呵呵,难得黄哥能问出这种问题!!决定解决之~~~~~~~~~~~~

    题目为(ACM/ICPC Regional Contest Southeastern European 2001. Problem C. Secret Numbers),原文如下:

Problem C

Secret Numbers

Problem

Two natural numbers a and b are chosen (1<a<b). Person M is told the multiple of a and b (a*b), and person S is told the sum of a and b (a+b). The discussion between M and S goes like this:
M: I do not know the numbers a and b.
S: I do not know them either, but I knew you would not know them.
M: Now I know the numbers!
S: Now I know them, too!

Input

The input file contains pairs of natural numbers x and y (2<=x<y<=550), one pair per line. The input is guaranteed to be correct.

Output

For each pair x, y, find all pairs of a and b, such that x<=a<b<=y and that the given discussion is possible. Write these pairs in a single line, and finish that line with "no more pairs." if there are a and b found in the given range, or write simply "no pairs." if there are not. Separate the numbers of a pair with a comma, terminate each pair with a semi-colon, and separate different pairs with a blank after the semi-colon, as shown in the example below.

Sample Input

2 10
2 20

Output for the Sample Input

no pairs.
4,13; no more pairs.

简单解释一下:

    有两个数a和b(1<a<b)。M先生知道a*b的值,S先生知道a+b的值,两人有如下的对话:
      M先生:  我不知道a和b的值。
      S先生:  我也不知道,而且之前我还知道你不知道。
      M先生:  我现在知道a和b的值了。
      S先生:  我现在也知道a和b的值了。
    给定x和y(2<=x,y<=550),求所有满足对话场景的(a,b)且x<=a<b<=y。假设二位先生都足够聪明且没有撒谎!


你有想法了吗???


    幸好足够聪明的博得先生,在参考了N本书后,终于搞定了这个问题!下面来分析一记:

    解题的关键是MS两位先生的四句话,而且这四句话是步步递进的,也就是任何满足后一句的数对,必然满足前一句!如果可以将这四句话用四个逻辑判别函数( f1(a,b)~f4(a,b) )表示,就可以在给定的范围内求出所有的满足f4(a,b)的数对!

    首先,根据题意先设有两个集合:
        M(a,b)={ (x,y)| x*y=a*b 且 1<x<y }
        S(a,b)={ (x,y)| x+y=a+b 且 1<x<y }

    可以得到如下表格:

MS两位先生的话 实现函数 条件 返回值
M:我不知道a和b的值。 bool f1(int a,int b) |M(a,b)|>1 true

else

false
S:我也不知道,而且之前我还知道你不知道。 bool f2(int a,int b) 1、f1(a,b)==true
2、|S(a,b)|>1
3、任取(p,q)∈S(a,b)使得f1(p,q)==true
true

else

false
M:我现在知道a和b的值了。 bool f3(int a,int b) 1、f2(a,b)==true
2、只有一对(p,q)∈M(a,b)
满足f2(p,q)==true
true

else

false
S:我现在也知道a和b的值了。 bool f4(int a,int b) 1、f3(a,b)==true
2、只有一对(p,q)∈S(a,b)
满足f3(p,q)==true
true

else

false

    具体的实现就看代码吧!

//ACM/ICPC Regional Contest Southeastern European 2001. 
//Problem C. Secret Numbers
//by BodeSmile 05.10.03
//
//        M(a,b)={ (x,y)| x*y=a*b 且 1<x<y }
//        S(a,b)={ (x,y)| x+y=a+b 且 1<x<y }

#include 
<iostream>
#include 
<cmath>

using namespace std;

#define MAXN 302500
#define MAXM 550

bool prime[MAXN];

//素数表的生成
void inline get_prime()
{
    
int i,j,k;
    prime[
0]=prime[1]=true;
    
for(i=4;i<MAXN;i+=2)
        prime[i]
=true;

    
for(i=3;i<MAXM;i+=2)
    
{
        
if(prime[i])
            
continue;
        k
=i+i;
        
for(j=i*i;j<MAXN;j+=k)
            prime[j]
=true;
    }

}


bool f1(int a,int b)
{
    
//|M(a,b)|>1
    if!prime[a] && ( (!prime[b])||(b==a*a)||(b==a*a*a) ) )
        
return false;
    
else
        
return true;
}


bool f2(int a,int b)
{
    
int tp;
    
if( f1(a,b) && (a+b)>6 )
    
{
        
//p、q均为质数,使用哥德巴赫猜想!
        
//(a+b为偶数,必然存在质数p和q,使:p+q==a+b)
        if( (a+b)%2==0 )
            
return false;
        
else if!prime[a+b-2] )
            
return false;
       
        
//p为质数,q=p*p或q=p*p*p 的情况
        tp=(int)sqrt((double)(a+b));
        
if( tp*(tp+1)==(a+b) && (!prime[tp]) )
            
return false;
        
for(tp=2;(tp+tp*tp*tp)<=(a+b);tp++)
        
{
            
if( prime[tp] )
                
continue;
            
if( (tp+tp*tp*tp)==(a+b) )
                
return false;
        }

        
//条件都满足,就返回true
        return true;
    }

    
else
        
return false;
}


bool f3(int a,int b)
{
    
int i;
    
double tp;
    
if( f2(a,b) )
    
{
        tp
=sqrt((double)(a*b));
        
for(i=2;i<tp;i++)
        
{
            
if( (a*b)%i!=0 )
                
continue;
            
if( a==i )
                
continue;
            
if( f2(i,(a*b)/i) )
                
return false;    //只有一对(p,q)∈M(a,b)满足f2(p,q)==true
        }

        
return true;
    }

    
else
        
return false;
}


bool f4(int a,int b)
{
    
int i;
    
if( f3(a,b) )
    
{
        
for(i=2;i<((a+b)/2);i++)
        
{
            
if( a==i )
                
continue;
            
if( f3(i,(a+b)-i) )
                
return false;    //只有一对(p,q)∈S(a,b)满足f3(p,q)==true
        }

        
return true;
    }

    
else
        
return false;
}


int main()
{
    
int tp;
    
int i,j;
    
int x,y;

    get_prime();

    
while(cin>>x>>y)
    
{
        tp
=0;
        
for(i=x;i<y;i++)
        
{
            
for(j=i+1;j<=y;j++)
            
{
                
if( f4(i,j) )
                
{
                    cout
<<i<<","<<j<<"";
                    tp
++;
                }

            }

        }

        
if(tp==0)
            cout
<<"no pairs.\n";
        
else
            cout
<<"no more pairs.\n";
    }


    
return 0;
}

    执行一下,输入两个数(2~550之间)比如输入2、100就可以知道在 2~100 之间,满足条件的有四组:(4,13)、(4,61)、(16,73)、( 64,73)。

    至此程序应该是对的了,但由于没有找到哪个Online Judge上有这题,所以并没有递交过。那就欢迎大家的指正了!!!

参考书目:《算法艺术与信息学竞赛》

posted on 2005-10-03 15:57  博得一笑  阅读(741)  评论(3编辑  收藏  举报