zoukankan      html  css  js  c++  java
  • 入门OJ 1261【埃及分数】

    描述

      在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数。


      如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的。
      对于一个分数a/b,表示方法有很多种,但是哪种最好呢?
      首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。
      如:
      19/45=1/3 + 1/12 + 1/180
      19/45=1/3 + 1/15 + 1/45
      19/45=1/3 + 1/18 + 1/30,
      19/45=1/4 + 1/6 + 1/180
      19/45=1/5 + 1/6 + 1/18.
      最好的是最后一种,因为1/18比1/180,1/45,1/30,1/180都大。
      给出a,b(0〈a〈b〈1000),编程计算最好的表达方式。

    输入输出格式

    输入

      一行包含a,b(0〈a〈b〈1000)。

    输出

      每组测试数据若干个数,自小到大排列,依次是单位分数的分母。

    输入输出样例

    输入样例1

    19 45

    输出样例1

    5 6 18
    

    解题思路

      首先要知道什么埃及分数,如果你没懂,这里有个传说:

      

      老人弥留之际,将家中11匹马分给3个儿子,老大1/2,老二1/4,老三1/6。二分之一是5匹半马,总不能把马杀了吧,正在无奈之际,邻居把自己家的马牵来,老大二分之一,牵走了6匹;老二四分之一,牵走了3匹;老三六分之一,牵走了2匹。一共11匹,分完后,邻居把自己的马牵了回去。即11/12=1/2+1/4+1/6。
    奇妙的埃及分数终于调动自己的潜在难度击败了敢于轻视他们的人们。并且给与嘲笑他的人以难堪的回答。
    ——————————————————————————摘自百度百科

      咳咳,这道题思路有点复杂,先看到题解。我DFS中的分子和分母是输入的分子和分母减去枚举的分子和分母后的情况。还有,因为我没有化简(有点懒)所以里面的变量都是long long。

      第23排:这里前面的比较是把剩余的分数化为分子为一的单位分数,在平均分给剩下的分数,如果剩下的都小于了当前最优解,就直接返回(至于为什么先平均分再化简,是因为这样更精确)。

          后一个比较是当前最小的分数大于最优解,那么就返回。

      第24排:这里的i是取max(pre,fm/fz),前者是上一个分母+1,后者是单位分数,这样的话如果fm/fz>pre,就可以避免减去这个分数后为负数的情况,有效的剪枝(遇到大数据真的快了几秒)。

      第34排:这里qwe是搜索层数,这里用了分支限界,可以保证取的解是分数数量最小的。

    题解

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 long long qwe,ans;
     4 bool flag;//判断有没有搜到 
     5 long long num[1009];//搜索过程中存储分母的数组 
     6 long long sum[1009];//最优解的存储分母的数组 
     7 void dfs(long long dep,long long fz,long long fm,long long pre)//深度,分子,分母,上一个分母
     8 {
     9     if(dep==qwe+1)//搜索完了 
    10     {
    11         if(fz==0)//分子也等于0 
    12         {
    13             flag=true;//搜到了 
    14             if(num[qwe]<sum[qwe])//如果最小的分数最大,则更优,就替换 
    15             {
    16                 for(long long i=1;i<=qwe;i++)
    17                     sum[i]=num[i];
    18                 ans=num[qwe];//记录最小的分数 
    19             }
    20         }    
    21         return;
    22     }
    23     if((fm*(qwe+1-dep))/fz>ans||num[dep]>ans)return;//剪枝操作,具体请见解题思路中 
    24     for(long long i=max(pre,fm/fz);i<=fm*(qwe+1-dep)/fz;i++) //也含有剪枝 ,具体请见解题思路中 
    25     {
    26         num[dep]=i;//记录分母 
    27         dfs(dep+1,fz*i-fm,fm*i,i+1);//继续搜索 
    28     }
    29 }
    30 int main()
    31 {
    32     long long a,b;
    33     cin>>a>>b;
    34     for(qwe=1;;qwe++)
    35     {
    36         sum[qwe]=99999999;//初始化成很大的数,一定要初始化,方便比较 
    37         ans=99999999;
    38         dfs(1,a,b,1);
    39         if(flag)break;//因为是分支限界,所以一旦搜到了就满足分数数量最小 
    40     }
    41     for(long long i=1;i<qwe;i++)
    42     {
    43         cout<<sum[i]<<" ";//输出 
    44     }
    45     cout<<sum[qwe]<<endl;//控制格式 
    46     return 0;
    47 }
  • 相关阅读:
    DOS命令
    利用cmd合并文件
    Word文档编辑
    初识Java
    变量、数据类型、运算符-2
    设计模式之策略模式
    设计模式之装饰者模式
    第18章 java I/O系统(3)
    第18章 java I/O系统(2)
    第四章 栈与队列3 (堆栈的应用)
  • 原文地址:https://www.cnblogs.com/hualian/p/11162756.html
Copyright © 2011-2022 走看看