Guess Number with Lower or Higher Hints

64 篇文章 0 订阅
22 篇文章 0 订阅

题目1 : Guess Number with Lower or Higher Hints

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

There is a game about guessing number between 1 and N. This game is played by two people A and B. When A guesses a number(e.g. 5), he needs to pay that amount of dollars($5). Then B will give a hint whether A's guess is lower, higher or correct. B will choose the hint that forces to gain maximal amount of earning as long as it's not conlict with previous hints.

Assume they are both smart enough. What is the minimal amount that A needs to pay to finish this game? That is, there is only one number left and A will surely guess it right. Careful: B does not have a fixed number in mind.  

输入

An integer N. (1 <= N <= 200)

输出

The minimal amount A needs to pay.

样例输入

5

样例输出

6

 

翻译:

在1和N之间有一个关于猜数的游戏,这个游戏是由A和B两个人玩的。当A猜一个数字(例如5)时,他需要支付那么多美元(5美元)。然后B会提示A的猜测是低的、高的还是正确的。B将选择一个提示,即只要不与先前的暗示相冲突,就会迫使人们获得最大的收入。假设他们都够聪明。A完成这个游戏所需要支付的最低金额是多少?也就是说,只剩下一个数字,而A肯定会猜对了。小心:B没有固定的数字。

 

题是一道类似“石子合并”的动态规划题目。

我们用f[l][r]表示A从[l, r]的范围中猜中B想的数,需要支付的最小的代价。

面对范围[l, r],A显然可以猜[l, r]的任意一个数,因为A足够聪明,所以他会选择其中代价最小的方案。

假设A猜的是k,那么他首先要支付$k。这时对于B,他显然不会说k就是答案(除非l=r=k)。B为了让自己的收益最大,会考虑f[l][k-1]和f[k+1][r]哪个比较大。

如果前者比较大,B就会说A猜大了,从而让A从[l, k-1]的范围再猜,代价是f[l][k-1];反之B就会说A猜小了,让A从[k+1, r]的范围再猜,代价是f[k+1][r]。

总之,如果A猜k,那么他需要支付的代价是k + max{f[l][k-1], f[k+1][r]}。

因为A足够聪明,所以他会选择其中代价最小的方案。也就是f[l][r] = min{k + max{f[l][k-1], f[k+1][r]} | k = l, l+1, ... r}。

于是我们按照以上转移方程进行动态规划即可。最后f[1][n]就是答案。

 

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        //动态规划
        int[][] pay = new int[n+1][n+1];
        for(int step = 1; step <= n; step++){
            for(int left = 1; left + step <= n; left++){
                int right = left + step;
                //遍历k
                pay[left][right] = Integer.MAX_VALUE;
                for(int k = left; k <= right; k++) {
                    int temp = 0;
                    if(k > left) temp = Math.max(pay[left][k-1],temp);
                    if(k < right) temp = Math.max(pay[k+1][right],temp);
                    pay[left][right] = Math.min(pay[left][right], k + temp);
                }
            }
        }
        System.out.println(pay[1][n]);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值