zoj 3356 Football Gambling II【枚举+精度问题】

题目:




Football Gambling II

Time Limit: 3 Seconds      Memory Limit: 65536 KB

The 2010 FIFA World Cup toke place between 11 June and 11 July 2010 in South Africa. Being a non-fans, asmn likes football gambling more than the football match itself. Of course, he won't use real money, he just gamble on the renren.com for fun using the virtual gold coin.

The rule of football gambling is simple. The bookmaker display three decimal numbers abc before the match between team X and team Y. Number a is the odds for team X will win the game. Number b is the odds for they will get a draw. Number c is the odds for team X will lose the game.

Odds means that if you bet x gold coins, you will get floor(odds * x) gold coins in total if you guess the right result, or you will get nothing.

The Odds of the online gambling is higher than that in the real gambling because the gold coins are virtual. After several gambling, asmn found that, sometimes the odds are too high that it is possible to find a way to bet on three result at the same time, so that he can win money whatever the result is.

After several gambling, asmn lose a lot of money. So he decide not to take any risk in the following gambling. Now, given that asmn has s gold coins before each match and the odds for this math, you should caluate the maximum number of coins asmn will have after the gambling in the worst situation.

Input

The input consists of N cases. The first line of the input contains a positive integer N(N <= 100). Each case contains an integer and three decimal numbers sab and c (0 < coins < 1000000, 1 < ab,c < 100), the meaning of which is described above. Each decimal number will have exactly two digits after the decimal point.

Output

For each case, output the maximum number of coins that asmn will have after the match in the worst situation.

Sample Input

4
3 3.30 3.30 3.30
30 3.30 3.30 3.30
1 30.00 50.00 20.00
42 2.00 3.00 7.00

Sample Output

3
33
1
43

Hint

In the third case, the odds are very high, but asmn has only one coin. If he join the gambling, he may lost his last coin.


Author: WANG, Yelei
Source: ZOJ Monthly, July 2010

题意:
每组测试数据 S 表示初始硬币个数,a,b,c分别表示题中所述赔率
赌博有三种结果,只可能猜中一种情况,猜中的 才可获利。
如果投 a,num个硬币【硬币不可拆分】并且结果是 a 那么可获利 floor(a*num)【即去掉小数部分】
对于 S 个硬币你可随意选择投或不投,或者投给哪一个
最后输出最糟的情况的获利【肯定是 >= S的】


思路:
后来看了这篇博客的博主写了下这个的想法: 点击打开链接
ax>x+y+z
by>x+y+x
cz>x+y+z
推出  1/a+1/b+1/c<1  注意是必要条件

有T组测试数据

开始比赛的时候想的是,按照每一个的赔率应该可以推出一个公式,从而决定每一种投多少硬币【为了保证一定结果不会比开始更糟,那么如果投,肯定是三种都要投的】,很显然的没有写出公式Orz

3355 判断是否稳赚不赔

同时如果上式成立,那么按b*cc*aa*b的比率去押注,就可以做到稳赚不赔,所以也是充分条件。


最后还是按照 mmchen 的枚举了,但是枚举如果用double  表示赔率,后面会出现很多精度问题,前面那位博主是每次算一次加入一点精度eps = 1e-5 到结果中。解决了这个问题,但是题目中也说了,赔率小数点后只会有两位,所以不想纠结了,还是按照mmchen的写法 ,先全部扩大 100 倍,避免了精度问题,最后的结果再除以100就好了

mmchen的博客:http://blog.acmore.net/?p=821


总的来说,就是从1枚举到 S,每次选一个盈利最小的,然后硬币就投入进去,同时更新盈利,这样就保证了无论结果是a,b,c哪一种,都能至少不输钱

code:

扩大一百倍
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

int main()
{
    int T;
    int s,a,aa,b,bb,c,cc;
    int ans;
    int num[5];

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d.%d%d.%d%d.%d", &s,&a,&aa,&b,&bb,&c,&cc);
        memset(num, 0, sizeof(num));

        a = a*100+aa;
        b = b*100+bb;
        c = c*100+cc;

        ans = s*100;
        int sa,sb,sc;
        for(int i = 1; i <= s; i++)
        {
            sa = a*num[1];
            sb = b*num[2];
            sc = c*num[3];

            if(sa <= sb && sa <= sc)
            {
                num[1]++;
            }
            else if(sb <= sa && sb <= sc)
            {
                num[2]++;
            }
            else if(sc <= sa && sc <= sb)
            {
                num[3]++;
            }

            sa = a*num[1];
            sb = b*num[2];
            sc = c*num[3];

            if(sa <= sb && sa <= sc)
            {
                ans = max(ans, sa+(s-i)*100);
            }
            else if(sb <= sa && sb <= sc)
            {
                ans = max(ans, sb+(s-i)*100);
            }
            else if(sc <= sa && sc <= sb)
            {
                ans = max(ans, sc+(s-i)*100);
            }

        }
        printf("%d\n", ans/100);
    }
    return 0;
}

加精度:
//各种精度问题Orz
//D	Accepted	180 KB	1950 ms	C++ (g++ 4.4.5)	1298 B	
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const double eps = 1e-5;
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int s;
        double a, b, c;
        int num[4];
        scanf("%d%lf%lf%lf", &s,&a,&b,&c);
        int ans = s;
        memset(num, 0, sizeof(num));

        int aa,bb,cc;

        for(int i = 1; i <= s; i++)
        {
            aa = a*num[1]+eps; //加一点精度
            bb = b*num[2]+eps;
            cc = c*num[3]+eps;

            if(aa <= bb && aa <= cc)
            {
                num[1]++;
            }
            else if(bb <= aa && bb <= cc)
            {
                num[2]++;
            }
            else if(cc <= aa && cc <= bb)
            {
                num[3]++;
            }

            aa = a*num[1]+eps;
            bb = b*num[2]+eps;
            cc = c*num[3]+eps;

            if(aa <= bb && aa <= cc)
            {
                ans = max(ans,s+aa-i);
            }
            else if(bb <= aa && bb <= cc)
            {
                ans = max(ans,s+bb-i);
            }
            else if(cc <= aa && cc <= bb)
            {
                ans = max(ans,s+cc-i);
            }

        }
        printf("%d\n", ans);
    }
    return 0;
}


 
posted @ 2013-07-23 17:01  free斩  Views(197)  Comments(0Edit  收藏  举报