[UESTC577]分数拆分 dfs迭代加深

该博客讨论了如何将分数拆分为单位分数的和,其中最优解的标准是加数尽可能少,且在加数数量相同的情况下,每个分数尽可能大。以1945为例,列举了几种拆分方法,并指出最后一种方法最佳。文章给出输入输出格式,说明了一个求解该问题的测试用例,涉及的数据范围为0<a<b<1000,测试数据不超过50组。
摘要由CSDN通过智能技术生成

分数拆分

Time Limit: 4000/2000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

任何一个分数都能才成若干个单位分数(形如1/a的, a是自然数)的和。

对于一个分数 ab ab,表示方法有很多种,但是哪种最好呢?

首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好,如果还是相同,那么第二小的分数越大越好,依次类推下去。

例如对于 1945 1945,下列方法都是合法的:

1945=13+112+1180 1945=13+112+1180

1945=13+115+145 1945=13+115+145

1945=13+118+130 1945=13+118+130

1945=14+16+1180 1945=14+16+1180

1945=15+16+118 1945=15+16+118

但是最好的是最后一种,因为 118 118 1180 1180 145 145 130 130 1180 1180都大。

现在给出 a,b a,b( 0<a<b<1000 0<a<b<1000),求最好的表达方式。

Input

第一行有一个整数 T T,表示有 T T( T50 T≤50)组测试数据,每组测试数据为一行包含 a,b a,b( 0<a<b<1000 0<a<b<1000)。

Output

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

Sample input and output

Sample Input Sample Output
1
19 45
5 6 18

Source

UESTC Training for Search Algorithm


电子科大的,讲课都安利他们oj上的题
说我还是写不好dfs
感觉很弱
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1005;
int T,a,b,md,f;
ll v[N],ans[N];
ll gcd( ll a, ll b ){
	return b == 0 ? a : gcd( b, a%b );
}
int minn( ll a, ll b ){
	return b/a + 1;
}
bool cmp( int d ){
	for( int i = d; i >= 0; i-- ) if( v[i] != ans[i] ) {
		return ans[i] == -1 || v[i] < ans[i];
	}
	return false;
}
bool dfs( int dep, int fa, ll x, ll y ){
	if( dep == md ){
		if( y % x ) return false;
		v[dep] = y/x;
		if(cmp(dep)) memcpy(ans,v,sizeof(ll)*(dep+1));
		return true;
	}
	bool flag = false;
	fa = max( fa, minn(x,y) );
	for( int i = fa; ; i++ ){
		if( y * (md+1-dep) <= x * i ) break;
		v[dep] = i;
		ll xx = x * i - y;
		ll yy = y * i;
		ll g = gcd(xx,yy);
		if(dfs( dep+1, i+1, xx/g, yy/g )) flag = true;
	}
	return flag;
}
int main(){
	scanf("%d", &T);
	while( T-- ){
		f = 0;
		scanf("%d%d", &a, &b);
		for( md = 1; md <= 100; md++ ) {
			memset(ans, -1, sizeof(ans));
			if(dfs(0, minn(a, b), a, b)){
				f = 1;
				break;
			}
		}
		if(f) {
			for( int i = 0; i <= md; i++ )
				printf("%d ", ans[i]);
			puts("");
		} else printf("-1\n");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值