题意解释:
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