Dynamic programming 寻找动态规划解

Dynamic programming 寻找动态规划解,dynamic-programming,Dynamic Programming,问题: 有一个由N块砖组成的堆栈。您和您的朋友决定使用此堆栈玩游戏。在这个游戏中,一个人可以从顶部移除1/2/3块砖块,玩家移除的砖块上的数字被添加到他的分数中。你必须以这样一种方式打球,你可以获得尽可能多的分数,同时你的朋友也会以最佳状态打球,你会采取第一步 输入格式 第一行将包含一个整数T,即测试用例的数量。每个测试用例对应两行,第一行包含一个数字N,即堆栈中元素的数量,下一行包含N个数字,即从上到下写在砖上的数字 输出格式 对于每个测试用例,打印一行包含您的最高分数。 我尝试过递归,但没有

问题: 有一个由N块砖组成的堆栈。您和您的朋友决定使用此堆栈玩游戏。在这个游戏中,一个人可以从顶部移除1/2/3块砖块,玩家移除的砖块上的数字被添加到他的分数中。你必须以这样一种方式打球,你可以获得尽可能多的分数,同时你的朋友也会以最佳状态打球,你会采取第一步

输入格式 第一行将包含一个整数T,即测试用例的数量。每个测试用例对应两行,第一行包含一个数字N,即堆栈中元素的数量,下一行包含N个数字,即从上到下写在砖上的数字

输出格式 对于每个测试用例,打印一行包含您的最高分数。 我尝试过递归,但没有成功

int recurse(int length, int sequence[5], int i) {
    if(length - i < 3) {
       int sum = 0;
       for(i; i < length; i++) sum += sequence[i];
       return sum;
    } else {
        int sum1 = 0;
        int sum2 = 0;
        int sum3 = 0;
        sum1 += recurse(length, sequence, i+1);
        sum2 += recurse(length, sequence, i+2);
        sum3 += recurse(length, sequence, i+3);
        return max(max(sum1,sum2),sum3);
    }
}



int main() {
    int sequence[] = {0, 0, 9, 1, 999};
    int length = 5;
    cout << recurse(length, sequence, 0);
    return 0;
}
int递归(int长度,int序列[5],int i){
if(长度-i<3){
整数和=0;
对于(i;icout乍一看,您的代码似乎完全错误,原因如下:

  • 玩家不被考虑。你拿一块砖头或者你的朋友拿一块砖头是不一样的(你必须最大化你的分数,当然总分数总是砖头上分数的总和)

  • 看起来只是某种形式的递归,没有记忆,这种方法显然会爆炸到指数计算时间(你使用的是“蛮力”方法,列举所有可能的游戏)

  • 动态规划方法显然是可行的,因为游戏的最佳延续并不取决于你是如何达到某个特定状态的

    • 下一个玩的是谁(你还是你的朋友)
    • 这堆砖还剩多少块
    通过这两个输入,你可以计算从那一点到游戏结束你能收集到多少

    1.轮到你了 你需要尝试收集1、2或3,并在对手必须选择的下一个游戏状态递归调用。在这三种情况中,你保留最高的结果

    2.轮到对手了 你需要模拟收集1块、2块或3块砖块,并在你必须选择的下一个游戏状态下递归调用。在这三种情况中,你保留了最低的结果(因为对手试图最大化他/她的结果,而不是你的结果)

    在函数的一开始,你只需要检查之前是否处理过相同的游戏状态,当从计算返回时,你需要存储结果。由于这种查找/记忆,搜索时间将不是指数型的,而是不同游戏状态数的线性(仅2*N,其中N是砖块数)

    在Python中:

    memory = {}
    bricks = [0, 0, 9, 1, 999]
    
    def maxResult(my_turn, index):
        key = (my_turn, index)
        if key in memory:
            return memory[key]
        if index == len(bricks):
            result = 0
        elif my_turn:
            result = None
            s = 0
            for i in range(index, min(index+3, len(bricks))):
                s += bricks[i]
                x = s + maxResult(False, i+1)
                if result is None or x > result:
                    result = x
        else:
            result = None
            for i in range(index, min(index+3, len(bricks))):
                x = maxResult(True, i+1)
                if result is None or x < result:
                    result = x
        memory[key] = result
        return result
    
    print maxResult(True, 0)
    
    memory={}
    砖块=[0,0,9,1999]
    def maxResult(我的车,索引):
    键=(我的旋转,索引)
    如果输入内存:
    返回存储器[键]
    如果索引==len(砖):
    结果=0
    elif my_turn:
    结果=无
    s=0
    对于范围内的i(索引,最小值(索引+3,长度(砖)):
    s+=砖[i]
    x=s+maxResult(假,i+1)
    如果结果为无或x>结果:
    结果=x
    其他:
    结果=无
    对于范围内的i(索引,最小值(索引+3,长度(砖)):
    x=maxResult(真,i+1)
    如果结果为无或x<结果:
    结果=x
    内存[键]=结果
    返回结果
    打印maxResult(真,0)
    
    乍一看,您的代码似乎完全错误,原因如下:

  • 玩家不被考虑。你拿一块砖头或者你的朋友拿一块砖头是不一样的(你必须最大化你的分数,当然总分数总是砖头上分数的总和)

  • 看起来只是某种形式的递归,没有记忆,这种方法显然会爆炸到指数计算时间(你使用的是“蛮力”方法,列举所有可能的游戏)

  • 动态规划方法显然是可行的,因为游戏的最佳延续并不取决于你是如何达到某个特定状态的

    • 下一个玩的是谁(你还是你的朋友)
    • 这堆砖还剩多少块
    通过这两个输入,你可以计算从那一点到游戏结束你能收集到多少

    1.轮到你了 你需要尝试收集1、2或3,并在对手必须选择的下一个游戏状态递归调用。在这三种情况中,你保留最高的结果

    2.轮到对手了 你需要模拟收集1块、2块或3块砖块,并在你必须选择的下一个游戏状态下递归调用。在这三种情况中,你保留了最低的结果(因为对手试图最大化他/她的结果,而不是你的结果)

    在函数的一开始,你只需要检查之前是否处理过相同的游戏状态,当从计算返回时,你需要存储结果。由于这种查找/记忆,搜索时间将不是指数型的,而是不同游戏状态数的线性(仅2*N,其中N是砖块数)

    在Python中:

    memory = {}
    bricks = [0, 0, 9, 1, 999]
    
    def maxResult(my_turn, index):
        key = (my_turn, index)
        if key in memory:
            return memory[key]
        if index == len(bricks):
            result = 0
        elif my_turn:
            result = None
            s = 0
            for i in range(index, min(index+3, len(bricks))):
                s += bricks[i]
                x = s + maxResult(False, i+1)
                if result is None or x > result:
                    result = x
        else:
            result = None
            for i in range(index, min(index+3, len(bricks))):
                x = maxResult(True, i+1)
                if result is None or x < result:
                    result = x
        memory[key] = result
        return result
    
    print maxResult(True, 0)
    
    memory={}
    砖块=[0,0,9,1999]
    def maxResult(我的车,索引):
    键=(我的旋转,索引)
    如果输入内存:
    返回存储器[键]
    如果索引==len(砖):
    结果=0
    否则如果
    
    import java.io.*;
    import java.util.*;
    import java.text.*;
    import java.math.*;
    import java.util.regex.*;
    
    public class Solution {
    
            public static void main(String[] args){
            Scanner sc=new Scanner(System.in);
            int noTest=sc.nextInt();
            for(int i=0; i<noTest; i++){
                int noBrick=sc.nextInt();
                ArrayList<Integer> arr=new ArrayList<Integer>();
                for (int j=0; j<noBrick; j++){
                    arr.add(sc.nextInt());
                }
                long sum[]= new long[noBrick];
                sum[noBrick-1]= arr.get(noBrick-1); 
                for (int j=noBrick-2; j>=0; j--){
                    sum[j]= sum[j+1]+ arr.get(j); 
                }
                long[] max=new long[noBrick];
                if(noBrick>=1)
                max[noBrick-1]=arr.get(noBrick-1);
                if(noBrick>=2)
                max[noBrick-2]=(int)Math.max(arr.get(noBrick-2),max[noBrick-1]+arr.get(noBrick-2));
                if(noBrick>=3)
                max[noBrick-3]=(int)Math.max(arr.get(noBrick-3),max[noBrick-2]+arr.get(noBrick-3));
                if(noBrick>=4){
                    for (int j=noBrick-4; j>=0; j--){
                        long opt1= arr.get(j)+sum[j+1]-max[j+1];
                        long opt2= arr.get(j)+arr.get(j+1)+sum[j+2]-max[j+2];
                        long opt3= arr.get(j)+arr.get(j+1)+arr.get(j+2)+sum[j+3]-max[j+3];
                        max[j]= (long)Math.max(opt1,Math.max(opt2,opt3));
                    }
                }
                long cost= max[0]; 
                System.out.println(cost);
            }
    
        }
    }
    
    # Base Cases
    dp[0] = a[0]
    dp[1] = a[0]+a[1]
    dp[2] = a[0]+a[1]+a[2]
    
    # build prefix sum array
    pre = [a[0]]
    for i in range(1,n):
        pre.append(pre[-1]+a[i])
    
    ans1 = a[i] + (pre[i-1] - dp[i-1]) 
    
    ans1 = a[i]+ (pre[i-1] - dp[i-1])   # if we pick only ith brick
    ans2 = a[i]+a[i-1]+(pre[i-2] - dp[i-2]) # pick 2 bricks
    ans3 = a[i]+a[i-1]+a[i-2]+(pre[i-3] - dp[i-3])    # pick 3 bricks
    
    a = map(int, raw_input().split())
    
    a.reverse()                 # so that a[0] is bottom brick of stack
    dp = [0 for x1 in xrange(n)]
    dp[0] = a[0]
    dp[1] = a[0]+a[1]
    dp[2] = a[0]+a[1]+a[2]
    
    # build prefix sum array
    pre = [a[0]]
    for i in range(1,n):
        pre.append(pre[-1]+a[i])
    
    for i in xrange(3,n):
        # We can pick brick i, (i,i-1) or (i,i-1,i-2)
        ans1 = a[i]+ (pre[i-1] - dp[i-1])   # if we pick only ith brick
        ans2 = a[i]+a[i-1]+(pre[i-2] - dp[i-2]) # pick 2
        ans3 = a[i]+a[i-1]+a[i-2]+(pre[i-3] - dp[i-3])    #pick 3
    
        # both players maximise this value. Doesn't matter who is playing
        dp[i] = max(ans1, ans2, ans3)
    print dp[n-1]