zoukankan      html  css  js  c++  java
  • USACO Section 2.1 Ordered Fractions 解题报告

    题目

    题目描述

    给定一个数N(1<=N<=160),需要产生所有的分数,这些分数的值必须要在0~1之间。而且每个分数的分母不能超过N。如下例所示:

    N = 5
    产生所有的分数:0/1 1/5 1/4 1/3 2/5 1/2 3/5 2/3 3/4 4/5 1/1
    

    样例输入

    5
    

    样例输出

    0/1
    1/5
    1/4
    1/3
    2/5
    1/2
    3/5
    2/3
    3/4
    4/5
    1/1
    

    解题思路

    这个题目最一开始我走了一些弯路,想得太复杂,结果第一发就超时了。后来静下心来算了想了下,发现枚举加排序速度就已经很快了。所以就实现了一下,通过。

    解题代码

    /*
    ID: yinzong2
    PROG: frac1
    LANG: C++11
    */
    #define MARK
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn = 170;
    int N;
    struct Frac {
        int num;
        int deno;
    };
    vector<Frac> lst;
    
    bool cmp(Frac A, Frac B) {
        int temp1 = A.num*B.deno;
        int temp2 = A.deno*B.num;
        return temp1 < temp2;
    }
    
    int GCD(int x, int y) {
        if (0 == y) return x;
        return GCD(y, x%y);
    }
    
    Frac afterGCD(Frac f) {
        int gcd = GCD(f.num, f.deno);
        f.num /= gcd;
        f.deno /= gcd;
        return f;
    }
    
    int main() {
    #ifdef MARK
        freopen("frac1.in", "r", stdin);
        freopen("frac1.out", "w", stdout);
    #endif // MARK
        while (cin >> N) {
            cout << "0/1" << endl;
            if (N != 1) {
                lst.clear();
                for (int i = N; i >= 2; --i) {
                    for (int j = 1; j < i; ++j) {
                        Frac f;
                        f.num = j;
                        f.deno = i;
                        lst.push_back(f);
                    }
                }
                sort(lst.begin(), lst.end(), cmp);
                int len = lst.size();
                Frac pre;
                pre = afterGCD(lst[0]);
                cout << pre.num << "/" << pre.deno << endl;
                // 对于排序后的数据进行去重
                for (int i = 1; i < len; ++i) {
                    lst[i] = afterGCD(lst[i]);
                    if (lst[i].num == pre.num && lst[i].deno == pre.deno) continue;
                    cout << lst[i].num << "/" << lst[i].deno << endl;
                    pre = lst[i];
                }
            }
            cout << "1/1" << endl;
        }
    }
    /*
    Executing...
       Test 1: TEST OK [0.000 secs, 4180 KB]
       Test 2: TEST OK [0.000 secs, 4180 KB]
       Test 3: TEST OK [0.000 secs, 4180 KB]
       Test 4: TEST OK [0.014 secs, 4180 KB]
       Test 5: TEST OK [0.014 secs, 4180 KB]
       Test 6: TEST OK [0.014 secs, 4180 KB]
       Test 7: TEST OK [0.028 secs, 4180 KB]
       Test 8: TEST OK [0.070 secs, 4180 KB]
       Test 9: TEST OK [0.056 secs, 4180 KB]
       Test 10: TEST OK [0.056 secs, 4188 KB]
       Test 11: TEST OK [0.140 secs, 4188 KB]
    
    All tests OK.
    */
    

    解题思路(type2)

    之后看了看官方的题解,发现第一个解法就是用的枚举加排序,但是有个优化的地方我之前没有考虑。我们最终枚举出来的所有的分数,分子分母应该都是互质的。所以我们对于所有分子分母互质的分数进行排序输出即可。

    解题代码

    /*
    ID: yinzong2
    PROG: frac1
    LANG: C++11
    */
    #define MARK
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn = 170;
    int N;
    struct Frac {
        int num;
        int deno;
    };
    vector<Frac> lst;
    
    bool cmp(Frac A, Frac B) {
        int temp1 = A.num*B.deno;
        int temp2 = A.deno*B.num;
        return temp1 < temp2;
    }
    
    int GCD(int x, int y) {
        if (0 == y) return x;
        return GCD(y, x%y);
    }
    
    int main() {
    #ifdef MARK
        freopen("frac1.in", "r", stdin);
        freopen("frac1.out", "w", stdout);
    #endif // MARK
        while (cin >> N) {
            cout << "0/1" << endl;
            if (N != 1) {
                lst.clear();
                for (int i = N; i >= 2; --i) {
                    for (int j = 1; j < i; ++j) {
                        Frac f;
                        f.num = j;
                        f.deno = i;
                        if (GCD(f.num, f.deno) != 1) continue;
                        lst.push_back(f);
                    }
                }
                sort(lst.begin(), lst.end(), cmp);
                int len = lst.size();
                for (int i = 0; i < len; ++i) {
                    cout << lst[i].num << "/" << lst[i].deno << endl;
                }
            }
            cout << "1/1" << endl;
        }
    }
    /*
    Executing...
       Test 1: TEST OK [0.000 secs, 4180 KB]
       Test 2: TEST OK [0.000 secs, 4180 KB]
       Test 3: TEST OK [0.000 secs, 4180 KB]
       Test 4: TEST OK [0.000 secs, 4180 KB]
       Test 5: TEST OK [0.000 secs, 4180 KB]
       Test 6: TEST OK [0.000 secs, 4180 KB]
       Test 7: TEST OK [0.000 secs, 4180 KB]
       Test 8: TEST OK [0.014 secs, 4180 KB]
       Test 9: TEST OK [0.028 secs, 4180 KB]
       Test 10: TEST OK [0.056 secs, 4180 KB]
       Test 11: TEST OK [0.140 secs, 4188 KB]
    
    All tests OK.
    */
    

    解题思路(type3)

    官方第二个解法很巧妙。是找到一个数学规律,直接可以打印所有的数字,时间复杂度为O(N)。具体可以看这里

    解题代码

    /*
    ID: yinzong2
    PROG: frac1
    LANG: C++11
    */
    #define MARK
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int N;
    
    void generateFrac(int num1, int denom1, int num2, int denom2) {
        if (denom1 + denom2 > N) return ;
        generateFrac(num1, denom1, num1+num2, denom1+denom2);
        cout << num1+num2 << "/" << denom1+denom2 << endl;
        generateFrac(num1+num2, denom1+denom2, num2, denom2);
    }
    
    int main() {
    #ifdef MARK
        freopen("frac1.in", "r", stdin);
        freopen("frac1.out", "w", stdout);
    #endif // MARK
        while (cin >> N) {
            cout << "0/1" << endl;
            generateFrac(0, 1, 1, 1);
            cout << "1/1" << endl;
        }
        return 0;
    }
    /*
    Executing...
       Test 1: TEST OK [0.000 secs, 4176 KB]
       Test 2: TEST OK [0.000 secs, 4176 KB]
       Test 3: TEST OK [0.000 secs, 4176 KB]
       Test 4: TEST OK [0.000 secs, 4176 KB]
       Test 5: TEST OK [0.000 secs, 4176 KB]
       Test 6: TEST OK [0.000 secs, 4176 KB]
       Test 7: TEST OK [0.000 secs, 4176 KB]
       Test 8: TEST OK [0.014 secs, 4176 KB]
       Test 9: TEST OK [0.028 secs, 4176 KB]
       Test 10: TEST OK [0.056 secs, 4176 KB]
       Test 11: TEST OK [0.140 secs, 4176 KB]
    
    All tests OK.
    */
    
  • 相关阅读:
    笔记35 跨重定向请求传递数
    判断邮箱的正则表达式
    按钮
    async await 的用法
    笔记34 Spring MVC的高级技术——处理multipart形式的数据
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Unique Binary Search Trees,Unique Binary Search Trees II
    Validate Binary Search Tree
    Populating Next Right Pointers in Each Node,Populating Next Right Pointers in Each Node II
  • 原文地址:https://www.cnblogs.com/yinzm/p/7487573.html
Copyright © 2011-2022 走看看