今天是返校第一天,早上我们又迎来了我们最最最....喜欢的dp练习赛。
今天的题,说简单吧,也不算简单,说难吧,是很难。
第一题。
这道题我的思路是这样的:利用一个数组f[i],表示第f[i]首歌可以达到音量i,那么就是两层循环递推。但是漏了一个很重要的问题。比如说f[2]=1,f[5]=1,此时音量改变量c[i]=3,那么递推到f[2]时,会将f[5]的值改为2,这样f[5]就不会对f[8]造成影响,那么这样得到的就是错解了。
正确代码如下:(初值f1[beginlevel]=f2[beginlevel]=0;
for(int i=1;i<=n;i++)
{
for(int j=m-c[i];j>=0;j--) //m表示最大音量,c[i]表示第i首歌的音量改变量
if(f1[j]==i-1) f1[j+c[i]]=i;
for(int j=c[i];j<=m;j++)
if(f2[j]==i-1) f2[j-c[i]]=i;
for(int j=0;j<=m;j++)
if(f1[j]==i||f2[j]==i) f1[j]=i,f2[j]=i;
}
将增加与减小分开处理,这样就有效避免了两者的相互影响。
第二题
这题我是听了大佬的讲解才开窍的,我之前的方法有漏洞,没有考虑重复压缩的情况。
大佬的方法很巧妙,看代码吧。
for(int i=1;i<=n;i++)
{
for(int j=a[i].w;j<=t*2;j++) //t*2的原因是下面求解时需要乘以5/4
dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v); //a[i].w表示第i块蛋糕的高度,a[i].v表示价值量
}
int ans=dp[t];
for(int i=1;i<=n;i++)
if(a[i].w>=k) ans=max(ans,dp[(t-a[i].w)*5/4]+a[i].v); //5/4非常巧妙 t-a[i].w表示压缩后的高度
巧妙得俺描述不出来,意会吧!
第三题
显然是区间dp,上代码!
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
a[i][j+n]=a[i][j];
a[i+n][j]=a[i][j];
a[i+n][j+n]=a[i][j];
}
//预处理
for(int i=1;i<=n*2;i++)
f[i][i+1]=1; //f[i][j]表示i或j能打败i+1到j-1之间的所有人
for(int i=n*2-2;i>=1;i--)
for(int j=i+2;j<=n*2;j++)
for(int k=i+1;k<=j-1;k++)
if((a[i][k]||a[j][k])&&f[i][k]==1&&f[k][j]==1)
f[i][j]=1;
蒟蒻解释不出来,意会吧!
第四题
这题...我没有想法。
发现我不算题解的题解字数是递减的。或许这就是题与题之间的差距吧..