TOJ 4453


题目标题:

Cards


题目连接:

http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=4453


题目类型:

模拟


数据结构:


思路分析:


类似于背包问题那样

一共5种卡片, 各有无限张

需要找出N张卡(  假设其中 1 有a1张, 2 有a2 张.... )

让其平均数 ( a1 *1 + a2 * 2 + a3 * 3 ...) / ( a1 + a2 + a3 ....)

精确的等于给定的值P,


既然这个P是符合规则的实数,且可能令N非常的大

所以不能单纯用背包思路来解决

首先要做的 先要吧P转换成整数, 并且假设一个整数来表示一共的张数

只要凑齐 这N张张数 并且值等于P的整数形式的 即可

并且需要符合最少张数这个条件


假如P为4.135

则我们知道 由 a1*1 + a2 * 2 ...得到的值除以总张数N就是 4.135 

所以可以表现成  ( a1*1 + a2 * 2 ... )  / ( a1 + a2 + a3 ....) = 4.135  ->   ( a1*1 + a2 * 2 ... )  /  N = 4.135 

要让张数最小 则对这个分数进行约分即可

则变成 4135 / 1000 

最后只要让 N = 1000, ( a1*1 + a2 * 2 ... )  = 4135 就可以

这里有个小技巧

就是让牌乘起来刚好要大过 4135 然后继续减掉它跟 4135的差 那必定就是答案

就比如

大过4135 的排是1000张5的牌 这样 这1000张的总值是5000 并不是4135

则我们需要保持张数 又要让值减到4135

我们只需减去5000 - 4135 就可以了

因为我们能凑出单位1的值 那就是 5-4

所以 要保持张数 又要让值减5000 - 4135

最简单的办法就是 减去 这么多张5 再加回这么多张4 就可以了

既然题目说任意一种情况即可

那这就是最简单的情况了


证明:

要从中选N张卡片 让他们的总值除以N等于P

则我们得到 总值/N = P

因为 卡的种类和张数都是整数 所以这里的总值和N也只能是整数


所以我们可以转化P = P  / 1 = P * 10000000 / 10000000;

这样的话 我们就得到 一个分子分母都是整数的分式 且答案等于P


那么这样的情况N并不是最小值 则我们对其进行约分

假设最简单分数 K/N = P  那我们就知道不存在更加少的情况了

因为

K/N=P 我们另N减去一个变量Z 就得到 K / ( N - Z ) = P  分母变小 我们需要让 分子变小来保持 分式的结果等于P 则得到 ( K - Y ) / ( N - Z ) = P

如果等式成立 则 原来的等式 K/N=P 必定不是最简分式

所以此时 的N 必然是正确且最小的


源代码:

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

typedef __int64 int64;

int64 _gcd( int64 a, int64 b )
{
	if( !b )
	{
		return a;
	}

	return _gcd( b, a % b );
}

int64 _cvrt( string c )
{
	int64 i, zz= 0;
	string tmp = "";
	
	for( int i = 0; i < c.length(); i ++ )
	{
		if( c[i] != '.' )
		{
			tmp += c[i];
		}
	}
	
	tmp = tmp + string( 10, '0' );
	
	for( i = 0; i < 10; i ++ )
	{
		zz = zz * 10 + tmp[i] - '0';
	}
	
	return zz;
}

int main()
{
	int64 i;
	double inp;
	string str = "";
	
	cin >> str;
	
	int64 arr[6] = { 0 };
	int64 fm = 1000000000, fz = _cvrt( str );
	
	int64 tmp = _gcd( fm, fz );
	
	fm /= tmp;
	fz /= tmp;

	for( i = 1; i <= 5; i ++ )
	{
		if( fm * i > fz )
		{
			arr[i] = fm;
			break;
		}
		else if( fm * i == fz )
		{
			arr[i] = fm;
			i = -1;
			break;
		}
	}

	if( i != -1 )
	{
		arr[i - 1] = i * fm - fz;
		arr[i] -= arr[i - 1];
	}

	for( i = 1; i <= 5; i ++ )
	{
		if( i != 1 )
		{
			printf( " " );
		}
		
		printf( "%I64d", arr[i] );
	}
	
	printf( "\n" );

	return 0;
}



注意:

这里输入的实数不能用double

因为 会产生丢失精度的情况

假设 输入4.9 则会变成4.89999999 的情况

所以只能用字符串输入 然后转换成整形


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值