• 375. Guess Number Higher or Lower II



    Aug-01-2019
    居然都4刷了,除了记得我做过之外完全没印象。

    居然做出来了。。
    对于n来说,我可以选1~n里任意一个,比如我选了3,对方一定会说答案在
    [12]或者[4n]中较大的那边,所以还是个MinMax题,总算稍微了有了点MinMax的感觉。
    但是1~n选哪个要遍历才行。。
    dp[n] = dp[1~i) + i + dp(i~n] (i = 1~n)

    class Solution {
        public int getMoneyAmount(int n) {
            int res = 0;
            int[][] dp = new int[n+1][n+1];
            
            dp[1][n] = getMinimalAmount(dp, 1, n);
            
            return dp[1][n];
        }
        
        public int getMinimalAmount(int[][] dp, int l, int r) {
            if (l > r) return 0;
            if (l + 1 == r) return l;
            if (l == r) return 0;
            if (dp[l][r] != 0) return dp[l][r];
            
            int tempMinimal = Integer.MAX_VALUE;
            for (int i = l; i <= r; i ++) {
                int leftPortion = getMinimalAmount(dp, l, i-1);
                int currentPay = i;
                int rightPortion = getMinimalAmount(dp, i+1, r);
                int tempPay = currentPay + Math.max(leftPortion, rightPortion);
                tempMinimal = Math.min(tempMinimal, tempPay);
            }
            dp[l][r] = tempMinimal;
            return dp[l][r];
        }
    }
    
    

    四刷?

    极大极小算法。。还是叫极小极大的。。

    首先要看怎么能保证赢。

    比如2个数,猜第一个猜第二个都能保证下一轮我们赢定了,为了少交钱,我们猜小的。

    比如3个数,猜第二个才能保证下一轮再猜一定能赢。

    比如4个数,怎么猜都不能保证下一轮一定赢,所以要猜两轮。第一轮猜1,2,3还是4就很讲究了。
    猜1就是num1 + dp[2]4
    猜2就是dp[1]1 + num2或者num[1] + dp[3]4
    ...

    4种里每种都算出来,看哪种花费最少,选最少的。
    而现在有N种。。。

    也是个game theory,我们2次决定中夹杂着对方的决定,对方的决定是对我们最不利的。

    所谓最不利,就是我们选一个数之后,答案比我们的数大还是小是由对方决定的,他会看看答案比我们大他赚钱多还是答案比我们小他赚钱多,然后选个他赚钱多的。

    所以选完数之后,我们的花费是当前选择的数,加上答案大的花费答案小的花费里大的那个。

    而我们的选择是,选哪个数花费最小。

    所以就是在每个最大值里选个最小的。

    public class Solution {
        public int getMoneyAmount(int n) {
            if (n <= 1) return 0;
            
            int[][] dp = new int[n+1][n+1];
            for (int[] num : dp) {
                Arrays.fill(num, -1);
            }
            
            dp[1][n] = guess(1, n, dp);
            
            return dp[1][n];
            
        }
        
        public int guess(int start, int end, int[][] dp) {
            if (start > end) return 0;
            if (end == start) return 0;
            if (end - start == 1) return start;
     
            if (dp[start][end] != -1) return dp[start][end];
            
            int res = Integer.MAX_VALUE;
            for (int i = start; i <= end; i++) {
                int left = guess(start, i-1, dp);
                int right = guess(i+1, end, dp);
                int makeSure = Math.max(left, right);
                res = Math.min(res, makeSure + i);
            }
            dp[start][end] = res;
            return res;
        }
    }
    

    一刷

    这个题操了。

    首先弄懂这个题要求什么就花了好久。

    是这个意思……

    给1到N的数,让你猜,不管你猜几,猜错了给你猜的数的钱。 猜8,错了,付8元。

    然后问你有多少钱才能保证一定能找到答案。
    其实可以理解为,不管答案是几,用你现有的钱,总能找到答案。

    举个例子,假如有1到10让我猜,现在我有一个亿,我肯定能猜出来。但是问题是我没那么多钱,至少有几块钱能保证我猜出来。

    这个题有一个假设,就是假设我不是傻逼。
    比如1-10 我猜7,小了,那么结果是8 9 10中一个。接下来我肯定猜9,因为如果没猜中,比9小的话答案就是8,否则是10.

    其实这个题,不用在乎答案是几,目的是要一个猜法,按这个猜法,一定能找到答案。
    比如刚才的例子,1-10,7+9=16是我们需要的资本,16元保证不管1-10里哪个数是答案,我们都能猜到,最多花16元。

    那么7+9是怎么来的?

    首先看9

    在猜了7之后,有2种可能,一种是答案比7小,一种是答案比7大。
    所以答案要么出自1-6 要么出自 8- 10
    为了 保证 一定能猜到,我们必须假设出自大的一边。
    此时的花费就是当前的7+max(1-6,8-10)

    那第一次的7是怎么来的,为什么第一次猜7?

    没什么好办法,只能遍历,从1-10 假如猜1会如何,猜2会如何,遍历一次,找到最小的起始点,这里又是最小了。
    其实我这种孤陋寡闻的弱智是第一次听说MiniMax这个概念,不是很理解,这个题想了好久才明白。

    看代码。。

    public class Solution {
        public int getMoneyAmount(int n) 
        {
        	int[][] dp = new int[n+1][n+1];
    
        	return helper(1,n,dp);
        	
        }
    
    
    
        public int helper(int left, int right, int[][] dp)
        {
        	if(left < right)
        	{
        		if(dp[left][right] != 0) return dp[left][right];	//we already calculated it once, just return.
    
        		int temp = Integer.MAX_VALUE;
    
        		for(int n = left; n <= right; n++)
        		{
        			temp = Math.min(temp,n+Math.max(helper(left,n-1,dp),helper(n+1,right,dp)));
    
        		}
    
        		dp[left][right] = temp;
        		return temp;
        	}
        	else
        	{
        		return 0; 	//not return left, becuase I guess the right one
        					//thus we dont need to pay for this guess
        	}
        }
    }
    
  • 相关阅读:
    六种排序
    洛谷 P1879 [USACO06NOV]玉米田Corn Fields
    [USACO06NOV]玉米田Corn Fields
    c++位运算符 | & ^ ~ && ||,补码,反码
    Blockade(Bzoj1123)
    割点(Tarjan算法)【转载】
    子串
    生命是什么
    怎样说话才打动人
    自控力
  • 原文地址:https://www.cnblogs.com/reboot329/p/5875875.html
Copyright © 2020-2023  润新知