给定n个书本的厚度,然后依次放到书架上,要么放在最左边要么放在最右边,或者不放,要求书的厚度是非递减的序列。然后问最多放置多少本书。
数字范围10^5,但是只有100个数字,我们先离散化一下。
然后对于放置一本书来言,就是要么增大下界,要么减小上界,或者上下界都不变。
那么我们可以采用dp[i][j]代表当前下界为i上界为j最多放置多少本书。
对于一个新的书,就是产生dp[a[i]][j],dp[j][a[i]]两种情况,都是dp[i][j]+1。考虑到不取,那么就是原先的复制过来,比较最大。
然后出了问题,因为转移方程写的,那么在j==a[i]的情况下,会被多加一次(代码注释地方),就很尴尬了,所以多开了一维代表运行到第几个数字...
我觉得可能这道题写成记忆化搜索的方式更为简单且易于理解。
#include<bits/stdc++.h>
using namespace std;
#define N 100500
map<int,int> mp;
int a[120],b[120];
int dp[103][103][103];
int main()
{
int t;
scanf("%d",&t);
for(int cas=1; cas<=t; cas++)
{
mp.clear();
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int cnt=1;
for(int i=1; i<=n; i++)
{
if(mp[b[i]]) continue;
mp[b[i]]=cnt++;
}
for(int i=1; i<=n; i++)
a[i]=mp[a[i]];
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=1; j<=cnt; j++)
{
for(int k=j; k<=cnt; k++)
{
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]);
if(a[i]>=j&&a[i]<=k)
{
dp[i][j][a[i]]=max(dp[i-1][j][k]+1,dp[i][j][a[i]]);//假如k==a[i],这个时候dp[j][k]会改变,下一步多加,所以要三维
dp[i][a[i]][k]=max(dp[i-1][j][k]+1,dp[i][a[i]][k]);
}
}
}
}
int ans=0;
for(int i=1; i<=cnt; i++)
{
for(int j=i; j<=cnt; j++)
{
ans=max(dp[n][i][j],ans);
}
}
printf("Case %d: %d\n",cas,ans);
}
return 0;
}