您的位置:首页 > Web前端

EOJ 1852 Solution Report --Ordered Fractions

2014-03-01 17:26 489 查看
代码看不清的请戳我的原文:http://linus-young.github.io/blog/2014/03/01/eoj-1852-solution-report-ordered-fractions/

csdn这排版没法用了,掀桌(╯‵□′)╯︵┻━┻


1. 问题描述

给定一个数 N , 从小到大列出 0 到 1 之间 分母不超过 N 的最简真分数,包括 0/1, 1/1


2. 解题思路


解法1

最简单的想法,生成所有有效分数,然后对其排序,输出。(0/1 和 1/1 可单独输出) 那么什么是有效分数呢,需要满足以下条件:

分母不超过 N

分子与分母互质

分子小于分母

所以我们用如下循环即可得到有效分数:

1
2
3
4

for(int i = 1; i <= n-1; i++)
for(int j = i+1; j <= n; j++)
if(gcd(i, j) == 1) // gcd denotes 最大公约数
/* store valid fractions here*/

那么问题是怎么存取分数呢?而且输出格式为: $i/j$ 很容易想到
struct
结构体。
因此我们定义如下结构体来存取分数:

1
2
3
4

struct fraction {
int numerator;
int denominator;
};

全部有效分数获得后,排序也很简单了,用个
qsort
或者
sort
即可。

1
2
3
45
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

//
//  main.cpp
//  eoj1852_struct
//
//  Created by whyisyoung on 2/27/14.
//  Copyright (c) 2014 whyisyoung. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;

struct fraction {
int numerator;
int denominator;
}frac[7820];

int gcd(int a, int b)
{
return (b == 0) ? a : (gcd(b, a % b));
}

int generate_fractions(int n)
{
int count = 0;

for(int i = 1; i <= n-1; i++) {
for(int j = i+1; j <= n; j++) {
if(gcd(i, j) == 1) {
frac[count].numerator      = i;
frac[count++].denominator = j;
}
}
}
return count;
}

int compare(const void* a, const void* b)
{
fraction *x = (fraction *)a;
fraction *y = (fraction *)b;
double frac_a = x->numerator * 1.0 / x->denominator;
double frac_b = y->numerator * 1.0 / y->denominator;
if(frac_a < frac_b)
return -1;
if(frac_a > frac_b)
return 1;
return 0;
}

int main(int argc, char const *argv[])
{
int n, count;

while(scanf("%d", &n) != EOF) {
count = generate_fractions(n);

cout << "0/1\n";

qsort(frac, count, sizeof(frac[0]), compare);

for(int i = 0; i < count; i++)
cout << frac[i].numerator << '/' << frac[i].denominator << endl;

cout << "1/1\n";
}
return 0;
}


解法2

其实一开始想到的是把 “i/j” 当作字符串处理的,于是问题就是找小数和字符串的对应关系,这好办,一个
map<double,
string>
就搞定了,而且由于 map 默认对 key 按升序排序,所以只要把这些有效分数加入到 map 即可,连排序的工作都省了,当然为此付出的代价就是多消耗了一些 memory。

1
2
3
45
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

//
//  main.cpp
//  eoj1852
//
//  Created by whyisyoung on 2/23/14.
//  Copyright (c) 2014 whyisyoung. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;

map<double, string> frac;

int gcd(int a, int b)
{
return (b == 0)?a:(gcd(b, a % b));
}

int generate_fractions(int n)
{
int size = 0;

for (int i = 1; i <= n-1; ++i) {
for(int j = i+1; j <= n; j++) {
if(gcd(i, j) == 1) {
char cstr[10];
sprintf(cstr, "%d/%d", i, j); // itoa(i, cstr, 10) is deprecated
string str(cstr);
frac[i*1.0 / j] = str;
size++;
}
}
}
return size;
}

int main(int argc, char const *argv[])
{
int n, size;
while(cin >> n) {
size = generate_fractions(n);

cout << "0/1\n";

map<double, string>::iterator it = frac.begin();

for( ; it != frac.end(); it++) {
cout << it->second << endl;
}

cout << "1/1\n";
}
return 0;
}


解法3

以前肖老师讲的,这题实际就是要输出 farey 数列 有两种生成办法:

递归生成:

1
2
3
45
6
7
8
9

int N;
void Feray(int a, int b, int c, int d)
{
if(b + d > N)
return ;
Feray(a, b, a+c, b+d);
cout << a+c << '/' << b+d << endl;
Feray(a+c, b+d, c, d);
}

主函数中只需调用这句即可
Feray(0,
1, 1, 1);


迭代生成:

1
2
3
45
6
7
8
9
10
11
12
13
14
15
16
17

void farey(int n)
{
int pa=0, pb=1, ca=1, cb=n;
int na, nb;

printf("%d/%d\n", pa, pb);
printf("%d/%d\n", ca, cb);
while(ca!=cb){
na = (pb+n) / cb * ca - pa;
nb = (pb+n) / cb * cb - pb;
printf("%d/%d\n", na, nb);
pa = ca;
pb = cb;
ca = na;
cb = nb;
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  EOJ feray