TOJ 4453

来源:互联网 发布:win10仿mac桌面dock 编辑:程序博客网 时间:2024/06/07 00:25


题目标题:

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