【P1763 埃及分数】题解

题目链接

题目

古埃及,人们使用单位分数的和(形如 1a 的,a 是自然数)表示一切有理数。如:23=12+16,但不允许 23=13+13,因为加数中有相同的。对于一个分数 ab,表示方法有很多种,但是哪种最好呢?首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。如:

1945=13+112+11801945=13+115+1451945=13+118+1301945=14+16+11801945=15+16+118

最好的是最后一种,因为 1181180,145,130,118 都大。
注意,可能有多个最优解。如:

59211=14+136+1633+1379859211=16+19+1633+13798

由于方法一与方法二中,最小的分数相同,因此二者均是最优解。

给出 a,b,编程计算最好的表达方式。保证最优解满足:最小的分数 1107

思路

方法就是爆搜。

可以用迭代加深搜索来实现,枚举总共用多少个分数,然后搜下去。

注意输入的数要先约分,不然我像我一样一直RE一个点。

总结

  1. 遇到此类题目,不要害怕,要勇敢去打。
  2. 对于题目中不确定的(例如个数),可以用迭代加深搜索,因为前面的全部搜一次都不够最后一层搜得大。
  3. 题目中涉及分数运算要经常记得通分。

Code


// Problem: P1763 埃及分数
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1763
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 10000010
int n, m, i, j, k; 
int ans[N], tot[N], flg; 

int gcd(int x, int y)
{
	while(y)
	{
		int z=x%y; 
		x=y; 
		y=z; 
	}
	return x; 
}

void dfs(int lmt, int k, int x, int y)
{
//	if(k==3) return ; 
//	if(k<2)
//	 printf(">%lld %lld %lld %lld\n", lmt, k, x, y); 
	if(k>lmt)
	{
		// printf("%lld %lld\n", x, y); 
		if(x==n&&y==m)
		{
			if(ans[lmt]<tot[lmt])
				for(int i=1; i<=lmt; ++i) tot[i]=ans[i]; 
			flg=1; 
		}
		return ; 
	}
	int xn=n*y-m*x, yn=m*y; 
	if(yn==0) return ; 
	int i, z, newx, newy;  
	// printf("(%lld, %lld<=i*%lld)\n", ans[k-1]+1, m*y, (n*y-m*x)); 
//	if(k<3)
//	 printf("%lld<=i<=%lld\n", max(ans[k-1]+1, yn/xn), yn*(lmt-k+1)/xn); 
	for(i=max(ans[k-1]+1, yn/xn); i<=yn*(lmt-k+1)/xn; ++i)
	{
		
		ans[k]=i; 
		newx=x*i+y; newy=y*i; 
		if(m*newx>n*newy) continue; 
		z=gcd(newx, newy); 
		if(z>1) newx/=z, newy/=z; 
//		 printf("(%lld) ", z); 
		dfs(lmt, k+1, newx, newy); 
	}
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	n=read(); m=read(); 
	k=gcd(n, m); n/=k; m/=k; 
	for(i=ans[0]=1; !flg; ++i)
	{
//		printf("%lld\n", i); 
		tot[i]=1e12, dfs(i, 1, 0, 1); 
	}
		
	// printf("%lld\n", i); 
	for(j=1; j<i; ++j) printf("%lld ", tot[j]); 
	return 0; 
}
posted @   zhangtingxi  阅读(403)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示