解题报告——记忆化搜索

今天517盯着我说:我觉得今天你会被抽到, 然后~我就真的被抽到了,还是一道不会的题。。。

有两堆牌,每堆牌有n张牌,alice和bob轮流从某堆牌的最上面或者最下面取牌,牌上面写的分数会被加到他们对应的总分里,alice和bob都是绝顶聪明的,假如alice先取牌,最终他的得分是多少。

输入格式:

第一行输入一个整数n

接下来两行每行包含n个数,分别表示两堆牌。

输出格式:

输出一个整数,表示alice的得分

样例输入:

3 
10 100 20 
2 4 3 

105
#include<bits/stdc++.h>
using namespace std;
int n, a[22], b[22], dp[22][22][22][22], last[22][22][22][22];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= n; i++)
       scanf("%d", &b[i]);
    for(int i = 1; i < n; i++)
       for(int j = 1; j < n; j++){
           for(int xa = 1; xa <= n - i; xa++){
               for(int xb = 1; xb <= n - i; xb++){
                   int ya = xa + i, yb = xb + i;
                   if(last[xa+1][ya][xb][yb] == 0) dp[xa][ya][xb][yb] = a[xa];
                   if(last[xa+1][ya][xb][yb] == 1)
                   if(dp[xa][ya][xb][yb] < dp[xa + 2][ya][xb][yb] + a[xa])
                   dp[xa][ya][xb][yb] = dp[xa + 2][ya][xb][yb] + a[xa], last[xa][ya][xb][yb] = 1;
                   if(last[xa+1][ya][xb][yb] == 2)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya - 1][xb][yb] + a[xa])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya - 1][xb][yb] + a[xa], last[xa][ya][xb][yb] = 1;
                   if(last[xa+1][ya][xb][yb] == 3)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya][xb + 1][yb] + a[xa])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya][xb + 1][yb] + a[xa], last[xa][ya][xb][yb] = 1;
                   if(last[xa+1][ya][xb][yb] == 4)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya][xb][yb - 1] + a[xa])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya][xb][yb - 1] + a[xa], last[xa][ya][xb][yb] = 1;

if(last[xa][ya - 1][xb][yb] == 0) dp[xa][ya][xb][yb] = a[ya];
                   if(last[xa][ya - 1][xb][yb] == 1)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya - 1][xb][yb] + a[ya])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya - 1][xb][yb] + a[ya], last[xa][ya][xb][yb] = 2;
                   if(last[xa][ya - 1][xb][yb] == 2)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya - 2][xb][yb] + a[ya])
                   dp[xa][ya][xb][yb] = dp[xa][ya - 2][xb][yb] + a[ya], last[xa][ya][xb][yb] = 2;
                   if(last[xa][ya - 1][xb][yb] == 3)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya - 1][xb + 1][yb] + a[ya])
                   dp[xa][ya][xb][yb] = dp[xa][ya - 1][xb + 1][yb] + a[ya], last[xa][ya][xb][yb] = 2;
                   if(last[xa][ya - 1][xb][yb] == 4)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya - 1][xb][yb - 1] + a[ya])
                   dp[xa][ya][xb][yb] = dp[xa][ya - 1][xb][yb - 1] + a[ya], last[xa][ya][xb][yb] = 2;

if(last[xa][ya][xb + 1][yb] == 0) dp[xa][ya][xb][yb] = b[xb];
                   if(last[xa][ya][xb + 1][yb] == 1)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya][xb + 1][yb] + b[xb])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya][xb + 1][yb] + b[xb], last[xa][ya][xb][yb] = 3;
                   if(last[xa][ya][xb + 1][yb] == 2)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya - 1][xb + 1][yb] + b[xb])
                   dp[xa][ya][xb][yb] = dp[xa][ya - 1][xb + 1][yb] + b[xb], last[xa][ya][xb][yb] = 3;
                   if(last[xa][ya][xb + 1][yb] == 3)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya][xb + 2][yb] + b[xb])
                   dp[xa][ya][xb][yb] = dp[xa][ya][xb + 2][yb] + b[xb], last[xa][ya][xb][yb] = 3;
                   if(last[xa][ya][xb + 1][yb] == 4)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya][xb + 1][yb - 1] + b[xb])
                   dp[xa][ya][xb][yb] = dp[xa][ya][xb + 1][yb - 1] + b[xb], last[xa][ya][xb][yb] = 3;

if(last[xa][ya][xb][yb - 1] == 0) dp[xa][ya][xb][yb] = b[yb];
                   if(last[xa][ya][xb][yb - 1] == 1)
                   if(dp[xa][ya][xb][yb] < dp[xa + 1][ya][xb][yb - 1] + b[yb])
                   dp[xa][ya][xb][yb] = dp[xa + 1][ya][xb][yb - 1] + b[yb], last[xa][ya][xb][yb] = 4;
                   if(last[xa][ya][xb][yb - 1] == 2)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya - 1][xb][yb - 1] + b[yb])
                   dp[xa][ya][xb][yb] = dp[xa][ya - 1][xb][yb - 1] + b[yb], last[xa][ya][xb][yb] = 4;
                   if(last[xa][ya][xb][yb - 1] == 3)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya][xb + 1][yb - 1] + b[yb])
                   dp[xa][ya][xb][yb] = dp[xa][ya][xb + 1][yb - 1] + b[yb], last[xa][ya][xb][yb] = 4;
                   if(last[xa+1][ya][xb][yb] == 4)
                   if(dp[xa][ya][xb][yb] < dp[xa][ya][xb][yb - 2] + b[yb])
                   dp[xa][ya][xb][yb] = dp[xa][ya][xb][yb - 2] + b[yb], last[xa][ya][xb][yb] = 4;
               }
           }
       }
    for(int i = 1; i < n; i++)
       for(int j = 1; j < n; j++)
           for(int xa = 1; xa <= n - i; xa++)
               for(int xb = 1; xb <= n - i; xb++) {
                    int ya = xa + i, yb = xb + i;
                    printf("%d %d %d %d %d\n", xa, ya, xb, yb, dp[xa][ya][xb][yb]);
               }
    printf("%d", dp[1][n][1][n]);
    return 0;
}

然后,我就在众目睽睽之下写下了这样的一份代码:别复制那连样例也过不去

所以进过各种思考(tijie)我终于贺到了一份简短的代码:

我们可以用前缀和快速的处理出区间的和, 因为每一个人都是绝顶聪明的,所以他们都会选择最利于自己的一步:

dp[1][n][1][n] = max(sum - 四个卡片中取一个后的dp值 + 这个值)

可以用记忆化搜索:附上贺的代码::

#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
int num1[22];
int num2[22];
int sum1[22];
int sum2[22];
int ans[22][22][22][22];
int n;
int dfs(int i,int j,int k,int h)
{
    int sum=sum1[j]-sum1[i-1]+sum2[h]-sum2[k-1];
    if(ans[i][j][k][h]!=0)
        return ans[i][j][k][h];
    int ans1=0;
    if(i<j){
        ans1=max(ans1,sum-dfs(i+1,j,k,h));
        ans1=max(ans1,sum-dfs(i,j-1,k,h));
    }
    if(i==j) ans1=max(ans1,sum-dfs(i+1,j,k,h));
    if(k<h)
    {
        ans1=max(ans1,sum-dfs(i,j,k+1,h));
        ans1=max(ans1,sum-dfs(i,j,k,h-1));
    }
    if(k==h) ans1=max(ans1,sum-dfs(i,j,k+1,h));
    return ans[i][j][k][h]=ans1;
}
 
int main()
{
   int t;cin>>t;
   while(t--)
   {
       memset(ans,0,sizeof ans);
       scanf("%d",&n);
       for(int i=1;i<=n;i++)
        scanf("%d",num1+i),sum1[i]=sum1[i-1]+num1[i];
        for(int i=1;i<=n;i++)
        scanf("%d",num2+i),sum2[i]=sum2[i-1]+num2[i];
       cout<<dfs(1,n,1,n)<<'\n';
   }
    return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值