04.12 dp练习赛

        今天是返校第一天,早上我们又迎来了我们最最最....喜欢的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;

        蒟蒻解释不出来,意会吧!

第四题


        这题...我没有想法。


        发现我不算题解的题解字数是递减的。或许这就是题与题之间的差距吧..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值