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;
}