USACO 2.1 Ordered Fractions

9 篇文章 0 订阅

        这道题被我无视了……实际上没什么特别的逻辑。

        思路就是记录分数,然后进行一个排序。然而,这道题容易坑掉的点在于,一旦不注意及时剪枝的话就会超时。


        我具体剪枝和trick是这样的:

        主要的剪枝是对分数的过滤。举个例子来说,2/3与4/6这两个分数是同一个。这里要用到的是欧几里得的辗转相除法,如果两个数字的最大公约数不为1的话,那么这个必定不是最优解,就可以不记录下来。


        在这边我做了一个小trick,也就是在记录分数组合的时候,是从最小值写到最大值,这样就能在排序的时候减少交换的次数。


        最后的排序操作,我使用的是冒泡,之所以用的它,是因为在记录数据的时候,大部分的数值其实已经排好了,需要交换的数量不会很多,这时候冒泡排序在排序完毕后立刻跳出的特性,可以让检查的次数比较少。(自我感觉)


        以下附上代码:

#include <iostream>
#include <fstream>
using namespace std;

struct P
{
    int a, b;
};

const int MAXN = 161;
P ps[MAXN*MAXN];
int n;
int N;

int getDivider(int n1, int n2)
{
    if (n1%n2 == 0)
        return n1 < n2 ? n1 : n2;
    getDivider(n2, n1%n2);
}

void bubbleSort()
{
    int i, j;
    P tmp;
    bool flag;

    for (i = 1; i < n-1; i ++) {
        flag = true;
        for (j = 0; j < n-1-i; j ++) {
            if (((float)ps[j+1].a)/ps[j+1].b < ((float)ps[j].a)/ps[j].b) {
                tmp = ps[j];
                ps[j] = ps[j+1];
                ps[j+1] = tmp;
                flag = false;
            }
        }
        if (flag)
            break;
    }
}

int main()
{
    ifstream fin ("frac1.in");
    ofstream fout ("frac1.out");
    int i, j;

    fin >> N;
    ps[n].a = 0;
    ps[n].b = 1;
    n ++;
    for (i = N; i > 1; i --) {
        ps[n].a = 1;
        ps[n].b = i;
        n ++;
    }
    for (i = 2; i < N; i ++) {
        for (j = N; j > i; j --) {
            if (getDivider(i, j) == 1) {
                ps[n].a = i;
                ps[n].b = j;
                n ++;
            }
        }
    }
    ps[n].a = 1;
    ps[n].b = 1;
    n ++;

    bubbleSort();

    for (i = 0; i < n; i ++)
        fout << ps[i].a << "/" << ps[i].b << endl;

    return 0;
}

        闲话时间,总觉得USACO的题目难度设置很不均匀,但也有可能是有我擅长不擅长的题目类型吧……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值