UVa OJ 138 - Street Numbers (门牌号)

Time limit: 3.000 seconds
限时3.000秒

 

Problem
问题

A computer programmer lives in a street with houses numbered consecutively (from 1) down one side of the street. Every evening she walks her dog by leaving her house and randomly turning left or right and walking to the end of the street and back. One night she adds up the street numbers of the houses she passes (excluding her own). The next time she walks the other way she repeats this and finds, to her astonishment, that the two sums are the same. Although this is determined in part by her house number and in part by the number of houses in the street, she nevertheless feels that this is a desirable property for her house to have and decides that all her subsequent houses should exhibit it.
有一个计算机程序员,她家所在的某条路上的住宅都在路的同一边,编号由1开始依次递增。她每天晚上都要出门溜狗,或向左走或向右走,直到街尾后返回。有一天溜狗时她计算了沿街的门牌号之和(不包括她家的),第二天她走了相反的方向也计算了门牌号之和,结果令她震惊——两次门牌号之和竟然相同。尽管这个结果是由沿街的房子数量以及她家的门牌号决定的,但她仍然觉得这非常奇妙,并决定将此作为以后选择住房的必要条件。

 

Write a program to find pairs of numbers that satisfy this condition. To start your list the first two pairs are: (house number, last number):
写一个程序来计算满足上述条件的参数。参数包含两个整数,第一个是她的房子的门牌号,第二个是最后一个房子门牌号。

         6         8
        35        49

 

Input and Output
输入与输出

There is no input for this program. Output will consist of 10 lines each containing a pair of numbers, each printed right justified in a field of width 10 (as shown above).
这个程序没有输入。输出前10个能满足上面条件的整数对,每对整数独占一行,每个整数都居右对齐,宽度为10个字符(示例如上)。

 

Analysis
分析

这道题可以用暴力搜索的方法来做,算法效率是O(n3),但事实上是可以用数论的方法来生成所有解的,下面将用最简单的数学语言进行介绍。设全部的房子数为n,她住的为k,那么按照题目的要求n和k必须满足:

  • 1 + 2 + ... + (k – 1) = (k + 1) + (k + 2) + ... + (n)    (1)

用等差数列求和公式Sn=n(a1+an)/2对(1)进行化简,得:

  • (k – 1)[1 + (k – 1)] / 2 = (n – k)[(k + 1) + n] / 2, 两边同乘以2
  • (k – 1)[1 + (k – 1)] = (n – k)[(k + 1) + n]    (2)

将(2)式再次化简,得:

  • 2k2 = n2 + n    (3)

题目就转化为求出满足(3)式的最小的前10对正整数:n和k。先将上式两边配方,移项得:

  • (2n + 1)2 – 2(2k)2 = 1    (4)

令:

  • x = 2n + 1,y = 2k  (5)

将(5)代入(4)式,可得:

  • x2 – 2y2 = 1    (6)

不定方程(6)是一个典型的佩尔(Pell)方程,要推导求解该方程需要数论的一些基本概念,篇幅所限不再赘述,相关内容请参见维基百科:佩尔方程。为了方便程序实现,应使用递归公式进行求解。易知方程(6)的最小一组正整数解为(x0=3, y0=2),将题目所给的最小一组解(n=8,k=6)代入(5)式可得方程的解为(17, 12)。经验算可知(也可由下面的公式对(x0, y0)进行迭代求出),(17, 12)恰好为(6)式的第二组正整数解。至此初始值(前两组(x, y)解)计算完毕,后面的(x, y)可用迭代公式求出:

  • xi+1 = xix0 + nyiy0
  • yi+1 = xiy0 + yix0    (7)

用(7)迭代出前10组(x, y),然后用(5)式进行反算:

  • n = (x – 1) / 2, k = y / 2    (8)

即可求得前10组n和k。算法实现中,注意保留前一次的x和y值。若在计算下一个y值前已完成x的迭代,那么y值的迭代将出现错误。此外由于本题没有输入,您也可以预先将答案生成,在程序中直接按格式输出结果,这样速度最快(不过有点无耻哈~)。

 

Solution
解答

#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
	//循环10次,计算出每一组数据,x0和y0为最小解,x和y为迭代解
	for (int i = 0, x0 = 3, y0 = 2, x = x0, y = y0, t; i < 10; ++i, x = t) {
		t = x * x0 + 2 * y * y0; //用t临时保存算得的x
		y = x * y0 + y * x0; //计算出y
		//用x和y解出n和k并输出
		cout << setw(10) << y / 2 << setw(10) << (t - 1) / 2 << endl;
	}
	return 0;
}

转载于:https://www.cnblogs.com/devymex/archive/2010/09/07/1818983.html

杭州电子科技大学在线评测系统(杭电OJ)中的题目1000-1100是一系列编程题,我将分别进行回答。 1000题是一个简单的入门题,要求计算两个整数的和。我们可以使用一个简单的算法,读取输入的两个整数,然后将它们相加,最后输出结果即可。 1001题是一个稍微复杂一些的题目,要求实现字符串的逆序输出。我们可以使用一个循环来逐个读取输入的字符,然后将这些字符存储在一个数组中。最后,我们可以倒序遍历数组并将字符依次输出,实现字符串的逆序输出。 1002题是一个求最大公约数的问题。我们可以使用辗转相除法来解决,即先求出两个数的余数,然后将被除数更新为除数,将除数更新为余数,直至两个数的余数为0。最后的被除数就是最大公约数。 1003题是一个比较简单的排序问题。我们可以使用冒泡排序算法来解决,即每次比较相邻的两个元素,如果它们的顺序错误就交换它们的位置。重复这个过程直至整个数组有序。 1100题是一个动态规划问题,要求计算给定序列中的最长上升子序列的长度。我们可以使用一个数组dp来保存到达每个位置的最长上升子序列的长度。每当遍历到一个位置时,我们可以将其和之前的位置比较,如果比之前位置的值大,则将其更新为之前位置的值加1,最后返回dp数组的最大值即可。 以上是对杭电OJ1000-1100题目的简要回答,涉及了一些基本的编程知识和算法思想。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值