poj1980

dfs+剪枝

题意:给定一个分数,问用分子为1的分数加和来构成这个分数有多少种方式。要求每种情况分数的个数不超过n,分母乘积不超过a。

分析:dfs+剪枝,记录当前剩余的需要构成的分数值,然后试图用所有的可以使用的名额平分这个剩余值,再试图用一个分数构成这个剩余值,这样就确定了我要枚举当前分母的范围。并随时检查所有分母的乘积是否超限。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
usingnamespace std;

#define maxn 10

struct Partition
{
longlong a, b;
Partition(
longlong aa, longlong bb) :
a(aa), b(bb)
{
}
Partition()
{
}
} par[maxn];

longlong ans;
longlong p, q, a, n;

booloperator<(const Partition &x, const Partition &y)
{
return x.a * y.b < y.a * x.b;
}

longlong gcd(longlong x, longlong y)
{
if (!x ||!y)
return x > y ? x : y;
for (longlong t; t = x % y; x = y, y = t)
;
return y;
}

Partition
abstract(Partition a, Partition b)
{
Partition ret;
ret.b
= a.b * b.b;
ret.a
= a.a * b.b - b.a * a.b;
longlong g = gcd(ret.a, ret.b);
ret.a
/= g;
ret.b
/= g;
return ret;
}

void dfs(longlong t, Partition left, longlong sum)
{
if (left.b / left.a * sum > a)
return;
if (left.a ==1&& left.b >= par[t -1].b && sum * left.b <= a)
{
ans
++;
}
if (t >= n)
return;
if ((n - t +1.0) * left.b / left.a < par[t -1].b)
return;
for (longlong i = max(par[t -1].b, left.b / left.a); sum * i <= a && (n - t +1.0) * left.b / left.a >= i; i++)
{
par[t].a
=1;
par[t].b
= i;
if (par[t] < left)
{
dfs(t
+1, abstract(left, par[t]), sum * i);
}
}
}

int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%lld%lld%lld%lld", &p, &q, &a, &n), p | q | a | n)
{
ans
=0;
par[
0].a = par[0].b =1;
longlong g = gcd(p, q);
dfs(
1, Partition(p / g, q / g), 1);
printf(
"%lld\n", ans);
}
return0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值