您的位置:首页 > 其它

TOJ 4453

2014-03-03 20:47 309 查看
题目标题:

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 的情况

所以只能用字符串输入 然后转换成整形
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  模拟题