POJ 1061 青蛙的约会(扩展欧几里得)

题目大意:

  就是说,给你两个起始的x和y,然后x每次增加m,y每次增加n,以及长度L,求出最小的变化次数T,有(x+m*T)-(y+n*T)==P*L.

解题思路:

  裸裸的扩展欧几里得。

  分析:假设跳了T次以后,青蛙1的坐标便是x+m*T,青蛙2的坐标为y+n*T。它们能够相遇的情况为(x+m*T)-(y+n*T)==P*L,其中P为某一个整数,变形一下

得到(n-m)*T+P*L==x-y   我们设a=(n-m),b=L,c=x-y,T=x,P=y.于是便得到ax+by==c。激动啊,这不就是上面一样的式子吗。

直接套用扩展欧几里得函数,得到一组解x,y。由于问题是问最少跳多少次,于是只有x是我们需要的信息。那么再想,x是最小的吗?

  答案是可能不是!那么如何得到最小解呢?  我们考虑x的所有解的式子: x=x0+b/d*t。x0是我们刚刚求到的,很显然右边是有个单调函数,当t为某一个与x正负性质相反的数时,可以得到最小的x。 令x的正负性质为正,那么x=x0-b/d*t1 (t1==-t)。令x==0,那么t=x0*d/b,最小的x等于x0减去t*b/d。这里得到的x可能是负数,如果是负数,我们再为它加上一个b/d即是所求答案了!

代码:

 1 # include<cstdio>

 2 # include<iostream>

 3 # include<fstream>

 4 # include<algorithm>

 5 # include<functional>

 6 # include<cstring>

 7 # include<string>

 8 # include<cstdlib>

 9 # include<iomanip>

10 # include<numeric>

11 # include<cctype>

12 # include<cmath>

13 # include<ctime>

14 # include<queue>

15 # include<stack>

16 # include<list>

17 # include<set>

18 # include<map>

19 

20 using namespace std;

21 

22 const double PI=4.0*atan(1.0);

23 

24 typedef long long LL;

25 typedef unsigned long long ULL;

26 

27 # define inf 999999999

28 

29 LL x,y,a,b,c,d;

30 LL n,m,X,Y,L;

31 

32 LL ext_gcd( LL a,LL b )

33 {

34     LL t,d;

35     if ( b==0 )

36     {

37         x = 1;

38         y = 0;

39         return a;

40     }

41     d = ext_gcd(b,a%b);

42     t = x;

43     x = y;

44     y = t-(a/b)*y;

45     return d;

46 }

47 

48 

49 int main(void)

50 {

51     while (cin>>X>>Y>>m>>n>>L )

52     {

53         a = n-m;

54         b = L;

55         c = X-Y;

56         d = ext_gcd(a,b);

57         if ( c%d!=0 )

58         {

59             printf("Impossible\n");

60             continue;

61 

62         }

63         x = x*(c/d);

64         y = y*(c/d);

65 

66         LL k = x*d/b;

67         k = x-k*b/d;

68         if ( k<0 )

69         {

70             k+=b/d;

71         }

72         cout<<k<<endl;

73     }

74 

75 

76     return 0;

77 }

 

你可能感兴趣的:(poj)