1444:埃及分数

本文分享了一道关于分数枚举的问题解决过程,通过迭代搜索并应用多种剪枝技巧找到最优解。从调试经历到最终代码实现,展示了作者在算法竞赛中的成长与心得。

闲话 (无兴趣可空降)

  • 这题折磨了我好久,为了调试,打了800多个字符(要知道我的正解才700多个字符),很短的代码,是我的心血。在漫漫OI路上,我总是被一些小错误,卡住一周甚至更多 也许是实力问题? ,但也在其中收获很多。最后,也要感谢我的老师,为我引路。好潦草的一段话
    ps.调试前后代码对比
调试中:
#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,s,ans[10001],sum[10001],d=0;
inline int gcd(int x,int y){
	if(!y) return x;
	return gcd(y,x%y);
}
inline void jqsh(int t,int k,int l,int x,int y){
	if(x<0||y<0) return;
	m=gcd(x,y);
	x=x/m;y=y/m;
	if(x==1&&t==k-1){
		cout<<x<<" "<<y<<endl;
		sum[++sum[0]]=y;
		for(int i=1;i<=sum[0];i++) cout<<sum[i]<<" ";
		cout<<endl<<sum[0]<<" "<<ans[0]<<endl;
		cout<<sum[sum[0]]<<" "<<ans[ans[0]]<<endl;
		if((sum[sum[0]]<ans[ans[0]]&&sum[0]==ans[0])||!ans[0]||ans[0]>sum[0]){
			ans[0]=sum[0];
			for(int i=1;i<=ans[0];i++) ans[i]=sum[i];
			if(d==1) cout<<"win"<<endl;
		}
		system("pause");
		sum[0]--;
		return;
	} 
	else if(t==k-1) return;
	for(int i=max(l+1,y/x-1);i<=(k-t)*y/x;i++){
		sum[++sum[0]]=i;
		if(d==1){
			cout<<"!!!"<<endl;
			cout<<t<<endl;
			cout<<i<<endl;
			cout<<x<<" "<<y<<endl;
			cout<<"!!!"<<endl;
			system("pause");
			jqsh(t+1,k,i,x*i-y,y*i);
		}
		if((i==5&&t==0&&k==3)){
		cout<<"****************"<<endl;
		cout<<t<<endl;
		cout<<i<<endl;
		cout<<x<<" "<<y<<endl;
		d=1;
		jqsh(t+1,k,i,x*i-y,y*i);
		cout<<"*****************"<<endl;
		system("pause");
		}
		jqsh(t+1,k,i,x*i-y,y*i);
		sum[0]--;
	}
	return;
}
int main(){
	scanf("%d %d",&a,&b);
	m=gcd(a,b);
	a=a/m;b=b/m;
//	for(int i=1;i<=a;i++)
	if(a==1){
		printf("%d\n",b);
		return 0;
	}
	for(int i=2;;i++){
		cout<<"*******"<<endl;
		cout<<i<<endl;
		system("pause");
		sum[0]=0;
		jqsh(0,i,1,a,b);
		cout<<"*******"<<endl;
		if(ans[0]) break;
	}
	for(int i=1;i<=ans[0];i++)
		printf("%d ",ans[i]);
	printf("\n");
	return 0;
}
正解
#include<bits/stdc++.h>
using namespace std;
long long n,m,a,b,s,ans[10001],sum[10001];
inline long long gcd(long long x,long long y){
	if(!y) return x;
	return gcd(y,x%y);
}
inline void jqsh(int t,int k,long long l,long long x,long long y){
	if(x<0||y<0) return;
	m=gcd(x,y);
	x=x/m;y=y/m;
	if(x==1&&t==k-1&&y!=l){ //y!=l避免分数相等
		sum[++sum[0]]=y;
		if((sum[sum[0]]<ans[ans[0]]&&sum[0]==ans[0])||!ans[0]||ans[0]>sum[0]){
			ans[0]=sum[0];
			for(int i=1;i<=ans[0];i++) ans[i]=sum[i];
		}
		sum[0]--; //调了那么多,原来是少了这一句 QWQ
		return;
	} 
	else if(t==k-1) return;
	for(int i=max(l+1,y/x-1);i<=(k-t)*y/x+1;i++){
		sum[++sum[0]]=i;
		jqsh(t+1,k,i,x*i-y,y*i); //分数通分
		sum[0]--; 
	}
	return;
}
int main(){
	scanf("%lld %lld",&a,&b);
	m=gcd(a,b);
	a=a/m;b=b/m;
	if(a==1){
		printf("%lld\n",b);
		return 0;
	}
	for(int i=2;;i++){
		sum[0]=0;
		jqsh(0,i,1,a,b);
		if(ans[0]) break;
	}
	for(int i=1;i<=ans[0];i++)
		printf("%lld ",ans[i]);
	printf("\n");
	return 0;
}
——————————————————————————————正文分割线————————————————————————

题干解析

  • 好恶心的题干,分数枚举从小到大,不能相等,最小的最大…

思路

  • 用迭代搜索,不断更新,分数要约分

剪枝

  • 剪枝1:分数约分时用gcd。
  • 剪枝2:循环上下限 (详见这位大神博客
  • 剪枝3:在搜索到只剩一个时,若x不为1,返回 (啊,好难描述详见代码吧)
  • 剪枝4:如果当前分子分母小于0,返回

ps.最重要的,如果不想见祖宗,请开long long

  • 代码在上面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值