greedy1042

题意解释:

John现有h个小时的空闲时间,他打算去钓鱼。钓鱼的地方共有n个湖,所有的湖沿着一条单向路顺序排列(John每在一个湖钓完鱼后,他只能走到下一个湖继续钓),John必须从1号湖开始钓起,但是他可以在任何一个湖结束他此次钓鱼的行程。

此题以5分钟作为单位时间,John在每个湖中每5分钟钓的鱼数随时间的增长而线性递减。每个湖中头5分钟可以钓到的鱼数用fi表示,每个湖中相邻5分钟钓鱼数的减少量用di表示,John从任意一个湖走到它下一个湖的时间用ti表示。

求一种方案,使得John在有限的h小时中可以钓到尽可能多的鱼。

选题原因:

经典的贪心例题,采用枚举+贪心的解题思路,题目难度适中。

此题还可以用DP解答,但与贪心相比,过程较复杂。

思路:

首先须注意的一点是,John只能向前走,返回的话只会增加John在路上的时间,因而减少他钓鱼的时间。因此此题解题步骤如下:

1、  枚举John经过的最后一个湖,每种情况减去所需步行的时间,剩下的就是钓鱼的时间。

2、  每5分钟选取钓鱼量最多的湖进行钓鱼,直到时间耗尽。

3、  在所有枚举的情况中选择钓鱼量最多的情况,即为问题的最优解。

此题需要注意的几个问题:

1、  如果解不唯一,选择在第一个湖耗时最多的解;如果仍旧存在不惟一解,选择在第二个湖耗时最多的解,以此类推。

2、  随着时间的增加,在某个湖中的钓鱼数可能会出现负数,此时应将该湖中每个时间单位的钓鱼数更新为零。

3、  在测试数据或程序运行的过程中可能出现每个湖鱼数全为0的情况,注意特别处理。

4、  枚举时,结束的标志是剩余时间<=0。

代码:

#include <stdio.h>

int n;//湖的个数

int h;//可用时间

int fi[30];//最初钓鱼量

int di[30];//单位时间鱼的减少量

int cfi[30];//对 fi 数组的保存

int ti[30];//ti[i] 表示从第 i 个湖到第 i+1 湖的时间

struct LAKENODE

{

int num[30];

int max;

}lake[30];//用结构体数组保存可能解

int GetMax(int p[], int i, int j)//返回数组 p 中最大数的编号

{

int cmax = p[i], loc = i;// loc :最大数的位置

for (int m = i + 1; m <= j; m++)

{

if (cmax < p[m])

{

cmax = p[m];

loc = m;

}

}

return loc;

}

void GetFish()

{

int i, j;

int T = h * 60, t, CT;

for(i = 1; i <= n; i++)//结构体数组初始化,全部置零

{

lake[i].max = 0;

for(int j = 1; j <= n; j++)

{

lake[i].num[j] = 0;

}

}

for (i = 1;i <= n; i++)//枚举结束湖的位置,从第一个湖到第n个湖

{

CT = T;

t = 0;

for (j = 1; j <= i; j++)

{

cfi[j] = fi[j];//将fi数组的值拷贝到cfi数组中

CT = (j < i) ? CT - ti[j] * 5 : CT;//计算除去走路时间后的剩余时间

}

while (t < CT)

{

int k = GetMax(cfi, 1, i);//找到钓鱼量最多的湖的编号

lake[i].max += cfi[k];//钓鱼总量增加在k湖一个单位时间钓到的鱼

lake[i].num[k] += 5;//停在k湖的时间增加一个单位时间

cfi[k] >= di[k] ? cfi[k] -= di[k] : cfi[k] = 0;//修改第k个湖在下一个时间单位中所能钓到的鱼

t += 5;//时间增加一个单位时间

}

}

for (i = 1; i <= n; i++)//将最大值拷贝到cfi数组中,用于查询真正最大值

{

cfi[i] = lake[i].max;

}

int la = GetMax(cfi, 1, n);//la:最优解下标

for (i = 1; i <= n; i++)

{

(i != n) ? printf("%d, ", lake[la].num[i]) : printf("%d", lake[la].num[i]);

}

printf("\nNumber of fish expected: %d\n\n", lake[la].max);

}

int main()

{

int i;

while (scanf("%d", &n) && n)

{

scanf("%d", &h);

for (i = 1; i <= n; i++)

{

scanf("%d", &fi[i]);

}

for (i = 1; i <= n; i++)

{

scanf("%d", &di[i]);

}

for (i = 1; i < n; i++)

{

scanf("%d", &ti[i]);

}

GetFish();

}

return 0;

}

补充:此解法效率47MS,136K,虽不能达到很高的效率,但整体思路比较直接明确。

greedy1042

时间: 2024-10-13 22:46:54

greedy1042的相关文章