#10009. 「一本通 1.1 练习 5」钓鱼

版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/84670563
【题目描述】

在一条水平路边,有 n 个钓鱼湖,从左到右编号为 1,2,…,n。佳佳有 H个小时的空余时间,他希望利用这个时间钓到更多的鱼。他从 1 出发,向右走,有选择的在一些湖边停留一定的时间(是 5 分钟的倍数)钓鱼。最后在某一个湖边结束钓鱼。佳佳从第 i 个湖到第 i+1个湖需要走 5×Ti分钟路,还测出在第 i 个湖停留,第一个 5 分钟可以钓到 Fi条鱼,以后每再钓 5分钟,可以钓到的鱼量减少 Di ,若减少后的鱼量小于 0,则减少后的鱼量为 0 。为了简化问题,佳佳假定没有其他人钓鱼,也没有其他因素影响他钓到期望数量的鱼。请编程求出佳佳最多能钓鱼的数量。

【输入格式】
第一行一个整数 n,表示湖的个数

第二行一个整数 H,表示佳佳的空闲时间

第三行有 n 个整数,依次表示每个湖第一个 5分钟能钓到鱼的数量

第四行有 n 个整数,依次表示以后的每5分钟钓鱼数量比前一个 5 分钟钓鱼数量减少的数量

第五行有 n-1 个整数,Ti 表示由第 i 个湖到第 i+1个湖需要花 5*Ti分钟的路程

【输出格式】
输出只有一行,表示佳佳最多能钓鱼的数量。
【样例输入】
3
1
4 5 6
1 2 1
1 2
【样例输出】
35
【样例解释】
在第 11个湖钓 15分钟,共钓得 4+3+2=9条鱼;

在第 2 个湖钓 10 分钟,共钓得 5+3=8条鱼;

在第 3 个湖钓 20 分钟,共钓得 6+5+4+3=18 条鱼;

从第 1 个湖到第 2 个湖,从第 2 个湖到第 3 个湖,共用时间 15 分钟,共得 35 条鱼,并且这是最多的数量。

【数据范围与提示】
对于 100% 的数据,2≤n≤100,1≤H≤20。

思路:说实在的,这道题我没有用贪心,虽然是贪心,因为dp会更加好理解。所以我在这里解释dp,但是也会放上贪心的代码。重点就是要搞清楚他的dp含义是,dp[i][j]表示第一个湖到第i个湖用了j个单位时间,钓的最多鱼要搞清楚他的每一次减少,使得总量形成了一个等差数列。大概就是这样,其他的看代码见识吧。

【代码一:dp】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(c<48 || c>57)
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>=48 && c<=57)
    {
        x=x*10+c-48;
        c=getchar();
    }
    return x*f;
}
int f[110],d[110]; 
int s[110],ss[110];
int dp[30][300];
//dp[i][j]表示第一个湖到第i个湖用了j个单位时间,钓的最多鱼 
int main()
{
    int n,h; n=read(); h=read(); h=h*12;
    //假设5分钟为一个单位时间,那么一小时60分钟里面有12个单位时间 
    for(int i=1;i<=n;i++) f[i]=read();
    for(int i=1;i<=n;i++) d[i]=read();
    s[1]=0; ss[1]=0;//初始化没有用过任何时间 
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&s[i]);
        /*
            从第i个湖走到i+1个用的时间
            说白了有i-1个数,不就是从第一个湖开始
            第一个数就是第一个湖到第二个湖走的时间
            第二个数就是第二个湖到第三个湖走的时间
            以此类推 
        */ 
        ss[i]=ss[i-1]+s[i];//ss[i]表示走路的时间
        /*
            因为我们把每个5分钟换成了单位时间
            所以其实就是之间把s[i-1]+s[i]全部加起来
            就是总共的走路时间 
        */ 
    } 
    memset(dp,0,sizeof(dp));//初始化 
    int ans=0;//记录数量 
    for(int i=1;i<=n;i++)//n个湖 
    {
        for(int j=1;j<=h-ss[i];j++)
        //h表示总时间,ss[i]表示走路的时间,h-ss[i]表示用在钓鱼的时间 
        {
            dp[i][j]=dp[i][j-1];//保存一下之前的状态 
            //或:dp[i][j]=dp[i-1][j];
            for(int k=0;k<=j;k++)//枚举在第i个池塘钓鱼的单位时间 
                if(f[i]-(k-1)*d[i]>0)
                {
                    dp[i][j]=max(dp[i][j],k*(f[i]+f[i]-d[i]*(k-1))/2+dp[i-1][j-k]);
                    //这一步就是为了更新当前拥有的鱼
                    /*
                        k*(f[i]+f[i]-d[i]*(k-1))/2这是一个等差数列
                        f[i]是第一个单位时间也就是钓的最多的一次鱼
                        接下来就是k*f[i]减去(1*d[i]+2*d[i]+3*d[i]+...(k-1)*d[i]) 
                        也就是f[i]+f[i]-f[i]*(k-1)
                        (最多的首项减去最少的末项*k个单位时间)/2
                        就是当前这个湖可以钓的最多的鱼 
                        dp[i-1][j-k]就是上一个湖钓的鱼 
                    */ 
                }
        }
        ans=max(ans,dp[i][h-ss[i]]);//记录每一次湖的答案 
    }
    printf("%d\n",ans);
    return 0;
}

【贪心代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
	char c=getchar();
	int x=0,f=1;
	while(c<48 || c>57)
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>=48 && c<=57)
	{
		x=x*10+c-48;
		c=getchar();
	}
	return x*f;
}
int t[110],f[110],d[110],a[110];
int main()
{
	int n,h; n=read(); h=read(); h*=12;
	int x;t[0]=0;
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) d[i]=read();
	for(int i=1;i<n;i++)
	{
		x=read();
		t[i]=t[i-1]+x;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++) f[j]=a[j];
		int kk=h-t[i-1]; int tt,maxx,sum=0;
		for(int j=1;j<=kk;j++)
		{
			maxx=0;
			for(int k=1;k<=i;k++)
				if(f[k]>maxx) maxx=f[k],tt=k;
			if(maxx==0)break;
			f[tt]-=d[tt]; sum+=maxx;
		}
		ans=max(ans,sum);
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42367531/article/details/84670563