[lintcode] 1556.猜数游戏 [Hard]

描述

为了进一步宣传,Lintcode决定策划一个猜数游戏。 游戏开始前,Lintcode会随机保密地选择一个不大于n的正整数x 让玩家来猜,并提供一个长度为n的数组aa[i]表示玩家选择整数i时需要付出的金钱。 每一轮游戏,玩家可以任意选择一个整数并付出相应的价钱,如果猜中了,即选择的数是x,则游戏结束,否则Lintcode的小姐姐会告诉玩家x比玩家所选择的数大或者小,随后玩家继续付钱选择下一个数,直到猜中x为止。游戏结束后,最后一轮猜数所付出的金钱a[x]将会被返还给玩家。 猜数的策略多种多样,而同一种策略当x为不同的数时需要付出的金钱也不一样。问能否找到一种最优策略,在最坏的情况下猜中数需要付出的代价最小?输出最小的代价。

 

样例

给出 a = [1,100,1],返回 2

解释:
可以选择的策略是:先猜1,如果没中再猜3,如果还是没中再猜2.
如果x = 1,则花费价钱 a[1] - a[1] = 0
如果x = 2,则花费价钱 a[1] + a[3] + a[2] - a[2] = 2
如果x = 3,则花费价钱 a[1] + a[3] - a[3] = 1
显然这是一个最优策略,在最坏情况下只需要花费金钱2,故返回2

如果选择其他的策略,比如先猜中间,再猜两边。当x = 1 或 3时,均需要付出金钱a[2] = 100
明显最坏情况下需要花费更多的金钱,故不是一个最优的策略。`

 

给出 a = [1,3,5,1,1,8,4] , 返回 5

解释:
此时的策略是先猜5,如果没猜中则根据小姐姐反馈的x与5的大小关系继续选择:
如果反馈x < 5,则说明 1 <= x <= 4,此时可以先猜4,如果没猜中再猜2,则可以保证最后能猜到x,最坏情况下的花费为:a[5] + a[4] + a[2] = 5
如果反馈x > 5,则说明 6 <= x <= 7,此时可以直接猜7,可以保证最后能猜到x,最坏情况下的花费为:a[5] + a[7] = 5
故返回 max{5,  5} = 5

思路

有一点博弈论的意思(max{min})。求的是最好的策略下最糟的情况。有一点绕, 也是一个经典的dp问题。

lintcode里面hard的题目其实很多是1.思路清奇 2.边界值特别麻烦。 代码量不见得高,但是很烧脑。

dp方程: dp[s,d] = min{max(i){dp[s,i-1], dp[i+1,d]} ) + a[i];

要注意一点是这个方程默认了两件事:

1. 取的值一定在中间(这个其实不一定),所以有一个取第一个值时候的情况

2. s-d的长度至少为3

这两点都很重要,需要考虑。

代码

class Solution {
public:
    /**
     * @param a: The array a
     * @return: Return the minimum cost
     */
    int min(int a, int b)
    {
        return a>b?b:a;
    }
    
    int max(int a, int b)
    {
        return a>b?a:b;
    }
     
    int getAnswer(vector<int> &a) {
        // Write your code here
        int n = a.size();
        int dp[201][201] = {0};
        
        for(int j=0; j<n-1; ++j)
        {
            dp[j][j+1] = a[j] < a[j+1]? a[j]:a[j+1];
        }
        

        for(int len = 3; len <= n ; ++len)
        {
            for(int start = 0; start < n-len+1; ++start)
            {
                int min=1<<29;
                
                int firstChoice = dp[start+1][start+len-1] + a[start];
                
                for(int i=start+1; i <= start+len-2; i++)
                {
                    int tmp = max(dp[start][i-1], dp[i+1][start+len-1]) + a[i];
                    
                    if(tmp < min)
                    {
                        min = tmp;
                    }
                }
                dp[start][start+len-1] = firstChoice < min? firstChoice:min;
            }
        }
        return dp[0][n-1];
    }
};

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值