2021年PAT乙级秋考 B-1 好数 (15 分) 题型:枚举 独立完成

78 阅读3分钟

题解

7-1 好数 (15 分)

好数是指由一对正整数a<ba<b按照 a2+ab+b2a^{2}+a*b+b^{2}这个规则生成的数,a 和 b 就称为这个好数的源头。例如 91 就是一个好数,因为 55+5×6+66=915*5+5×6+6*6 = 91,于是数对56(5,6)就是 91 的源头。而对于一个好数,其源头并不一定唯一,例如19(1,9)就是 91 的另一个源头。 本题就要求你编写程序,判断一个给定的数字是否好,并且输出好数的所有源头。

输入格式

输入在第一行给出一个不超过 100 的正整数 N,随后 N 行,每行给出一个不超过 104的正整数。

输出格式

对于每一个输入的数字,如果其是好数,则首先在一行中输出 Yes,然后每行输出它的一个源头,格式为 a b,按 a 的递增顺序输出;否则在一行中输出 No和比该数大的最小的好数,其间以空格分隔,然后每行输出这个好数的一个源头,格式同上。

输入样例

3
1
91
50

输出样例

No 7
1 2
Yes
1 9
5 6
No 52
2 6

思想

我刚开始是这样想的:

t = (i * i) + (i * j) + (j * j);

如果t大于了x(输入的样例值),那么以后i,j再怎么迭代,通过计算都得不到x这个值了,那么就保存一下大于x的值maxn,保存一下此时的i,j,然后退出循环。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int>PII;
int n;
int flag;
int maxn;
vector<PII>v;


bool cmp(PII a, PII b) {
	return a.first < b.first;
}

int main() {
	cin >> n;
	while (n--) {
		flag = 0;
		maxn = 0;
		int t = 0;
		int idx = 0, idy = 0;

		int x;
		cin >> x;

		for (int i = 1; i <= 100; i++) {
			for (int j = 1; j <= 100; j++) {

				if (i < j) {
					t = (i * i) + (i * j) + (j * j);
				}
				//	cout << "t: " << t << endl;
				if (t == x) {
					flag = 1;
					v.push_back({i, j});
				} else  if (t > x) {
					maxn = t;
					idx = i, idy = j;
					break;
				}
			}
			if (flag == 0)
				break;
		}

		sort(v.begin(), v.end(), cmp);

		if (flag) {
			cout << "Yes" << endl;
			for (auto &it : v) {
				cout << it.first << " " << it.second << endl;
			}
		} else {
			cout << "No" << endl;
			cout << maxn << endl;
			cout << idx << " " << idy << endl;
		}

	}

	return 0;
}

image.png 但是这样是错的,就拿第三个样例x=50举例,上面的代码计算出来50不是“好数”。并且大于50的最小“好数”是50,i,j为1,7。

而题目提供的答案是:大于x=50的最小“好数”是52,i,j是2,6。

Debug

如下图所示:

当i=1,j=7的时候,此时t值是57,57虽然大于50,但是此刻我们不能结束循环,把57赋给maxn。

因为我们可以发现i=2,j=6时得到的t值52比57更小,是更满足条件的。

image.png

因此我们要把break去掉,加一个min()函数。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int>PII;
int n;
int flag;
int maxn;
int cnt;
vector<PII>v;


bool cmp(PII a, PII b) {
	return a.first < b.first;
}

int main() {
	cin >> n;
	while (n--) {
		flag = 0;
		maxn = 0x3f3f3f3f;
		int t = 0;
		int idx = 0, idy = 0;
		v.clear();
		cnt = 1;

		int x;
		cin >> x;

		for (int i = 1; i <= 100; i++) {
			for (int j = 1; j <= 100; j++) {

				if (i < j)
					t = (i * i) + (i * j) + (j * j);

				if (t == x) {
					flag = 1;
					v.push_back({i, j});
					cnt++;
				} else  if (t > x) {
					maxn = min(maxn, t);
					if (t == maxn) {
						idx = i, idy = j;
					}
				}
			}
		}

		sort(v.begin(), v.end(), cmp);

		if (flag) {
			cout << "Yes" << endl;
			for (auto &it : v) {
				cout << it.first << " " << it.second << endl;
			}
		} else {
			cout << "No" << endl;
			cout << maxn << endl;
			cout << idx << " " << idy << endl;
		}

	}

	return 0;
}

image.png