[bzoj]1270: [BeijingWc2008]雷涛的小猫

原题链接:1270: [BeijingWc2008]雷涛的小猫

看到这个题,首先想到的就是动态规划(直觉)。

一、O(n^3)算法

而且这道题的状态转移方程也很好想:dp[i][j]表示高度为i,在j棵树上吃到的最大柿子数,num[i][j]表示在i棵树上j高度上的柿子数。

dp[i][j]=max{dp[i][j],dp[i+1][j]+num[i][j],dp[i+del][k]+num[i][j]};

下面是丑陋的超时代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,h,del,tmp,t;
int tree[2009][2009],dp[2009][2009];
void read(int &a){
    a=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){a=a*10+ch-'0';ch=getchar();}
    return;
}
int main()
{
    read(n);read(h);read(del);
    for(int i=1;i<=n;i++){
        read(tmp);
        for(int j=1;j<=tmp;j++){
            read(t);
            tree[i][t]++;
        }
    }
    for(int i=h;i>0;i--){
        for(int j=1;j<=n;j++){
            if(i==h){
                dp[i][j]=tree[j][i];
                continue;
            }
            for(int k=1;k<=n;k++){
                tmp=dp[i+1][j]+tree[j][i];
                if(i+del<=h)t=dp[i+del][k]+tree[j][i];
                else t=0;
                dp[i][j]=max(dp[i][j],max(tmp,t));
            }
        }
    }
    t=0;
    for(int i=1;i<=n;i++){
        t=max(t,dp[1][i]);
    }
    cout<<t<<endl;
    return 0;
}


二、O(n^2)算法

注意到不需要枚举上一步是从哪棵树转移过来的,只需要知道上面那一层的最大柿子数即可。

用lev[h]保存h高度的最大柿子数,now[i]表示跳到现在这棵树能吃到的最大柿子数。

now[j]=max{lev[i-del]+num[j][i]};

lev[i]=max{now[j]1<=j<=n};

最后输出lev[1]即为最后答案。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,h,del,tmp,t;
int tree[2009][2009],lev[5001],now[5001];
void read(int &a){
    a=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){a=a*10+ch-'0';ch=getchar();}
	return;
}
int main()
{
	read(n);read(h);read(del);
	for(int i=1;i<=n;i++){
		read(tmp);
		for(int j=1;j<=tmp;j++){
			read(t);
			tree[i][t]++;
		}
	}
	for(int i=h;i>0;i--){
		t=(i+del<=h)?lev[i+del]:0;
		for(int j=1;j<=n;j++){
			now[j]=max(now[j],t)+tree[j][i];
			lev[i]=max(lev[i],now[j]);
		}
	}
	printf("%d",lev[1]);
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值