1. 程式人生 > >Guess Number with Lower or Higher Hints

Guess Number with Lower or Higher Hints

題目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]);
    }
}