捡金币

这里写图片描述
80分做法
DP本格子是从上个时间能够到达该格子的位置拓展出来的,可以闪现也可以步行(注意可以不动)
对这些状态取max即可
我们枚举时间,f[t][i][j][k]表示第t秒站在(i,j),已经用了k次闪现所获得的最大金币数
转移方程见代码,还是比较容易理解的。(对于 t 我是从零开始存的)
时间复杂度:T*C*W*n*n ≈ 5*10^7 ,60%,3s大概是能过的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
#define INF 1000000007
using namespace std;
int n,C,W,T,ans;
int s[101][26][26];
int f[101][26][26][151];//f[t][i][j][k]表示第t秒站在(i,j),已经用了k次闪现所获得的最大金币数 
int MAX(int &x,int y){if(y>x) x=y;}//取大 
bool judge(int x,int y)
{
    if(x<=n&&x>=1&&y<=n&&y>=1) return 1;
    return 0;
}
int main()
{
    scanf("%d%d%d%d",&n,&C,&W,&T);
    for(int i=1;i<=T;i++) 
    for(int j=1;j<=n;j++) 
    for(int k=1;k<=n;k++) scanf("%d",&s[i][j][k]);

    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[0][i][j][0]=s[1][i][j];
    for(int t=1;t<T;t++)
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        for(int k=0;k<=W;k++)
        {
            MAX(f[t][i][j][k],f[t-1][i][j-1][k]+s[t+1][i][j]);//右走 
            MAX(f[t][i][j][k],f[t-1][i][j+1][k]+s[t+1][i][j]);//左走 
            MAX(f[t][i][j][k],f[t-1][i+1][j][k]+s[t+1][i][j]);//下走 
            MAX(f[t][i][j][k],f[t-1][i-1][j][k]+s[t+1][i][j]);//上走 
            MAX(f[t][i][j][k],f[t-1][i][j][k]+s[t+1][i][j]);//不动 
            for(int p=1;p<=C;p++)//闪现 
            {
                if(k-p>=0)
                {
                    if(judge(i,j-p*2)) MAX(f[t][i][j][k],f[t-1][i][j-p*2][k-p]+s[t+1][i][j]);
                    if(judge(i,j+p*2)) MAX(f[t][i][j][k],f[t-1][i][j+p*2][k-p]+s[t+1][i][j]);
                    if(judge(i-p*2,j)) MAX(f[t][i][j][k],f[t-1][i-p*2][j][k-p]+s[t+1][i][j]);
                    if(judge(i+p*2,j)) MAX(f[t][i][j][k],f[t-1][i+p*2][j][k-p]+s[t+1][i][j]); 
                } 
            }
        } 
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    for(int k=0;k<=W;k++)
    MAX(ans,f[T-1][i][j][k]);
    printf("%d",ans);
    return 0; 
}

100(优化闪现)
确定x,y中的一个状态,以另一个状态和k为横纵坐标会发现从上个状态闪现出来的是一个斜换行排列。闪现不用枚举c次,直接用单调队列维护最大值即可

#include <cstdio>
#define inf 1000000007
using namespace std;
int n,t,w,c;
int map[102][26][26];
int dp[2][26][26][151]; 
int l,r;
int dl[9999];
int qc[9999],cnt,tag;
int vis[99][99];
void init()
{
    l=1,r=0;
    dl[1]=-inf;
    dl[0]=inf;
} 
void max(int &x,int y)
{
    if(y>x) x=y;
    return;
}
inline int read()
{
    int data=0,w=1; char ch=0;
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data*w;
}
void push(int x)
{
    dl[++r] = x;
    qc[r] = 1;
    dl[r+1] = -inf;
    while (dl[r] >= dl[r-1])
    {
        qc[r-1] += qc[r];
        dl[r-1] = dl[r];
        dl[r--] = -inf;
    }
    if (++cnt > c) if (--qc[l] == 0) dl[l++] = inf;
}
void min_c(int t)
{
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      for(int k=0;k<=w;k++)
       dp[t][i][j][k]=-inf;
}
void Instantaneous_movement1(int t,int x)
{ 
    tag++; 
    for(int j=1;j<=n;j++)
     for(int k=0;k<=w;k++)
      if(vis[j][k]!=tag)
       {
        init();
        int jj=j,kk=k;
        while(jj<=n&&kk<=w)
        {
            vis[jj][kk]=tag;
            max(dp[t][x][jj][kk],dl[l]);
            push(dp[t^1][x][jj][kk]);
            jj+=2,kk++;
        }
       }
    tag++; 
    for(int j=n;j>=1;j--)
     for(int k=0;k<=w;k++)
      if(vis[j][k]!=tag)
       {
        init();
        int jj=j,kk=k;
        while(jj>=1&&kk<=w)
        {
            vis[jj][kk]=tag;
            max(dp[t][x][jj][kk],dl[l]);
            push(dp[t^1][x][jj][kk]);
            jj-=2,kk++;
        }
       }   
}
void Instantaneous_movement2(int t,int y)
{ 
    tag++; 
    for(int i=1;i<=n;i++)
     for(int k=0;k<=w;k++)
      if(vis[i][k]!=tag)
       {
        init();
        int ii=i,kk=k;
        while(ii<=n&&kk<=w)
        {
            vis[ii][kk]=tag;
            max(dp[t][ii][y][kk],dl[l]);
            push(dp[t^1][ii][y][kk]);
            ii+=2,kk++;
        }
       }
    tag++; 
    for(int i=n;i>=1;i--)
     for(int k=0;k<=w;k++)
      if(vis[i][k]!=tag)
       {
        init();
        int ii=i,kk=k;
        while(ii>=1&&kk<=w)
        {
            vis[ii][kk]=tag;
            max(dp[t][ii][y][kk],dl[l]);
            push(dp[t^1][ii][y][kk]);
            ii-=2,kk++;
        }
       }
}
void walk(int t,int time)
{
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
    for(int k=0;k<=w;++k)
    {
    max(dp[t][i][j][k],dp[t^1][i-1][j][k]);
    max(dp[t][i][j][k],dp[t^1][i+1][j][k]);
    max(dp[t][i][j][k],dp[t^1][i][j-1][k]);
    max(dp[t][i][j][k],dp[t^1][i][j+1][k]);
    max(dp[t][i][j][k],dp[t^1][i][j][k]);
    dp[t][i][j][k]+=map[time][i][j];
    }
}
int main()
{
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值