zoukankan      html  css  js  c++  java
  • 【Vijos-P1308】埃及分数-迭代加深DFS+分数表示法

    测试地址:埃及分数

    做法:乍一看这道题,有点懵,因为不知道到底有多少个1/a才能组成这个分数,而BFS的空间耗费实在是太巨大了,因此我们就可以用迭代加深的思想来解决:在最外层枚举搜索的深度(即分数的个数),在这一层中搜索解,如果找不到解就继续加深,找到解则输出最优的解。而这题用浮点数存储分数的话会有各种奇怪的错误,所以我们可以用两个数a,b分别表示分数的分子和分母。在搜索时,我们记录前几层搜索后所剩下的分数la/lb(即a/b-1/x1-1/x2-...),设这一层所枚举的分母为i,则易发现以下不等式:1/i ≤ la/lb,(深度上限-已经取过的分数数量)*(1/i)>(la/lb),由于la,lb,i都是整数,所以:i≥lb/la,b*(深度上限-已经取过的分数数量)>a*i,这些就可以确定i的范围了。还需要注意,i还要大于上一层的分母,所以枚举时要从max(上一层分母+1,lb/la)开始搜索(要注意lb/la的计算)。那么,如何计算剩余数x/y=la/lb-1/i呢?就像我们小学学的一样通分即可:la/lb-1/i=(la*i)/(lb*i)-lb/(lb*i)=(la*i-lb)/(lb*i),所以x=(la*i-lb),y=(lb*i)。要注意约分,即x,y都除以gcd(x,y),这是为以下的剪枝做准备:如果搜到最后只剩一层,就无需枚举,查看剩余数的分子是否是1即可,这就体现出约分的重要性了。由于题目中要求最大分母最小,且与此同时分母的字典序要最小,由于我们枚举时就是按字典序查找的,所以我们不用考虑字典序的问题,而最大分母最小这一个条件很好判断,有更好解的时候直接替换即可。

    以下是本人代码(别看上面讲了那么一堆,实际上程序不长...):

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 999999999
    using namespace std;
    long long a,b,depth,dion[101]={0},ans[101]={0};
    bool flag=0;
    
    long long gcd(long long a,long long b)
    {
      return b==0?a:gcd(b,a%b);
    }
    
    void dfs(long long la,long long lb,long long step)
    {
      if (step+1==depth)
      {
        if (la==1)
    	{
    	  dion[step+1]=lb;flag=1;
    	  if (dion[step+1]<ans[step+1]||ans[step+1]==0)
    	    memcpy(ans,dion,sizeof(dion));
    	}
    	return;
      }
      long long first=lb%la?lb/la+1:lb/la;
      for(long long i=max(dion[step]+1,first);;i++)
      {
        if (lb*(depth-step)<=i*la) break;
    	dion[step+1]=i;
    	long long nxta,nxtb,g;
    	nxta=la*i-lb,nxtb=lb*i;
    	g=gcd(nxta,nxtb);
    	dfs((long long)nxta/g,(long long)nxtb/g,step+1);
      }
    }
    
    int main()
    {
      scanf("%lld%lld",&a,&b);
      long long g=gcd(a,b);
      
      dion[0]=1;
      for(depth=1;;depth++)
      {
        dfs((long long)a/g,(long long)b/g,0);
    	if (flag) break;
      }
      
      for(int i=1;i<=depth;i++)
        printf("%lld ",ans[i]);
      
      return 0;
    }
    


  • 相关阅读:
    [asp.net] 网页自动刷新总结
    内容页中修改母版页内容
    [asp.net] 页面传值方法小记
    [VSS2005] 源代码管理bin文件夹里的.dll总是被签出,不能同时编译解决办法
    [asp.net] 设置与获取CheckBoxList多选的值
    [转] asp.net中repeater按钮传值与分页
    [asp.net] 验证控件的属性及用法
    [asp.net] 格式化repeater字段显示
    VPS绑定中文域名方法
    M/T法测速经典解析(转)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793891.html
Copyright © 2011-2022 走看看