中国计量大学“中竞杯”程序设计竞赛补题

F 爬塔
高川最喜欢的游戏当属 Slay the Spire,这是一款爬塔游戏,你需要从一座塔的底部一直爬到顶部,在爬塔的过程中,塔的每一层都有许多的宝物等你来拿。

高川从塔的左侧开始攀爬,从底部爬到顶部,再从右侧从顶部逐步下到底部。塔总共有 n 层,每一层都有很多宝物从左到右排列。在左侧攀爬时,他只能从每层的最左边按顺序取宝物,在右侧下降时,他只能从每层的最右边按顺序取宝物。每个宝物都有一个价值,他最多拿 m 个宝物,他想知道自己从塔上下来时,最多可以拿的宝物价值和是多少
题解:
一开始我用的是队列求
后来我又用的是栈
但是都WA了

#include<bits/stdc++.h>
#define ll long long
//#define speed_up ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const long long MAXN = 1e5 + 7;

int main()
{
    int n,m;
   cin>>n>>m;
   deque<int>v[n];
   for(int i=0;i<n;i++)
   {
       int x;
       cin>>x;
       for(int j=0;j<x;j++)
       {
           int c;
           cin>>c;
           v[i].push_back(c);
       }
   }
   int sum=0;
   for(int i=1;i<=m;i++)
   {
       int max=0;
       int maxn=0;
       int falg=0;
       for(int j=0;j<n;j++)
       {
           int nn=v[j].size()-1;
           if(nn>=0)
           {
               //前面的相等
              if(v[j][0]>=max)
              {
                  int m1=0,m2=0;
                  //计算它本身的m1
                  int k=v[j].size();
                  if(k<m-i)
                  {
                      for(int j1=0;j1<k;j1++)
                      {
                          m1=m1+v[j][j1];
                      }
                  }
                  else
                  {
                      for(int j1=0;j1<m-i;j1++)
                      {
                           m1=m1+v[j][j1];
                      }
                  }
                  //计算最大值的
                  k=v[maxn].size();
                  if(k<m-i)
                  {
                      for(int j1=0;j1<k;j1++)
                      {
                          m2=m2+v[maxn][j1];
                      }
                  }
                  else
                  {
                      for(int j1=0;j1<m-i;j1++)
                      {
                           m2=m2+v[maxn][j1];
                      }
                  }
                  if(m1>=m2)
                  {
                      max=v[j][0];
                      maxn=j;
                      falg=0;
                  }
              }
              //后方寻找
              if(v[j][nn]>=max)
              {
                  int m1=0,m2=0;
                  //计算它本身的m1
                  int k=v[j].size();
                  if(k<m-i)
                  {
                      for(int j1=0;j1<k;j1++)
                      {
                          m1=m1+v[j][j1];
                      }
                  }
                  else
                  {
                      for(int j1=k-m+i;j1<k;j1++)
                      {
                          m1=m1+v[j][j1];
                      }
                  }
                  //计算最大值的
                  k=v[maxn].size();
                  if(k<m-i)
                  {
                      for(int j1=0;j1<k;j1++)
                      {
                          m2=m2+v[maxn][j1];
                      }
                  }
                  else
                  {
                      for(int j1=k-m+i;j1<k;j1++)
                      {
                          m2=m2+v[maxn][j1];
                      }
                  }
                  if(m1>=m2)
                  {
                      max=v[j][nn];
                      maxn=j;
                      falg=nn;
                  }
              }
          }
       }
          sum=sum+max;
          //cout<<sum<<endl;
          if(falg==0)
          {
           v[maxn].pop_front();
          }
         else
          {
           v[maxn].pop_back();
          }
   }
   cout<<sum<<endl;
}

后来又改用vector求但是又WA了

#include<bits/stdc++.h>
#define ll long long
#define speed_up ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const long long MAXN = 1e5 + 7;

int main()
{
   int n,m;
   cin>>n>>m;
   vector<int>v[100];
   for(int i=0;i<n;i++)
   {
       int x;
       cin>>x;
       for(int j=0;j<x;j++)
       {
           int c;
           cin>>c;
           v[i].push_back(c);
       }
   }
   vector<int> v1;
   for(int i=n-1;i>=0;i--)
   {
       for(int j=0;j<v[i].size();j++)
       {
           v1.push_back(v[i][j]);
       }
   }
   int max=0;
   for(int i=0;i<=m;i++)
   {
       int j=m-i;
       int sumi=0;
       int sumj=0;
       for(int t=0;t<i;t++)
       {
           sumi=sumi+v1[t];
       }
       for(int t=v1.size()-1;t>v1.size()-1-j;t--)
       {
           sumj=sumj+v1[t];
       }
       if(sumi+sumj>=max)
       {
           max=sumi+sumj;
           //cout<<max<<endl;
       }
   }
   cout<<max<<endl;
}

后来看了网上大佬的思路和代码
题解:
因为每一层只能从左往右或者从右往左的顺序取宝物
可以先计算出每一层宝物价值的前缀和与后缀和分别表示从左往右与从右往左取宝物的价值和
接着维护一个ans数组,ans[i][j]表示第i层取j件宝物所能达到的价值最大值
最后进行DP

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2+10;
const int maxm = 1e4+10;

int a[maxn][maxn];
int x[maxn],ans[maxn][maxn];
int pref[maxn][maxn],suf[maxn][maxn];
int dp[maxm];

int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&x[i]);
		for(int j=1;j<=x[i];j++){
			scanf("%d",&a[i][j]);
			pref[i][j]=pref[i][j-1]+a[i][j];
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=x[i];j>=1;j--)
			suf[i][j]=suf[i][j+1]+a[i][j];

	for(int i=1;i<=n;i++)
		for(int j=0;j<=x[i];j++)
			for(int k=0;j+k<=x[i];k++)
				ans[i][j+k]=max(ans[i][j+k],pref[i][j]+suf[i][x[i]-k+1]);

	for(int i=1;i<=n;i++)
		for(int j=m;j>0;j--)
			for(int k=x[i];k>0;k--)
				if(k<=j)
					dp[j]=max(dp[j],dp[j-k]+ans[i][k]);

	printf("%d\n",dp[m]);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值