LightOJ 1106 Gone Fishing 贪心, DP, 堆优化 2017年1月23日

来源:互联网 发布:淘宝3000多的实体娃娃 编辑:程序博客网 时间:2024/05/17 20:13

题目链接: https://vjudge.net/problem/LightOJ-1106
题意
给出n个湖,John最开始在第一个湖并且有h个小时的时间,每个湖初始可以钓到f只鱼,每单位时间可以钓到的鱼减少d只(单位时间为5分钟,不足d只时减少为0),从第i个湖到第i+1个湖需要t[i]单位时间。求最多能够钓到鱼的数量和在每个湖花费的时间。
数据
输入第一行表示数据组数 T,T <= 100
对于每组测试数据,第一行为n和h,2 <= n <= 25,1 <= h <= 16
接下来一行为n个整数f[i],0 <= f[i] <= 1000
接下来一行为n个整数d[i],0 <= d[i] <= 1000
接下来一行为n-1个整数t[i],0 < t[i] < 192
输入
3
2 1
10 1
2 5
2
4 4
10 15 20 17
0 3 4 3
1 2 3
4 4
10 15 50 30
0 3 4 3
1 2 3
输出
Case 1:
45, 5
Number of fish expected: 31
Case 2:
240, 0, 0, 0
Number of fish expected: 480
Case 3:
115, 10, 50, 35
Number of fish expected: 724

解题方法: 1, 贪心,堆优化(由于数据比较小,可以直接暴力)
首先我们可以枚举要走过湖泊数X,然后算出从1到X的时间。那么在这个前提下,我们可以认为fisher可以从一个湖泊“瞬间转移”到另一个湖泊,即在任意一个时刻可以从1到X中任选一个钓鱼。
此时,走路的时间确定了,钓鱼的次数就确定了(每次5分钟),然后每次都选取f[i]最大的钓,这种贪心的思想最终能够得到一个钓鱼序列。
你可能会跟我一样有一个疑问:因为就算是在这种情况下求出的钓鱼序列 为 1 ,5,6, 2, 3, 2,7 ,你可能会认为到了湖泊6之后再回到湖泊2可能要再花时间而且题目也不允许,但是这只是钓鱼序列,我们可以用 1 2 2 3 5 6 7 来实现这种钓鱼序列。
复杂度 O(n * n * h)
代码如下:

#include <bits/stdc++.h>using namespace std;#define rep(i, a, b) for(int i = a; i <= b; i++)#define mep(i, a, b) for(int i = a; i < b; i++)#define uep(i, a, b) for(int i = a; i >= b; i--)#define cls(a, b) memset(a, b, sizeof(a))int f[30], d[30], t[30];int T, n, h, ks;int maxtime, ans_time[30], fishtime;int main(){    ks = 0;    scanf("%d", &T);    while(T--){        scanf("%d%d", &n, &h);        rep(i, 1, n) scanf("%d", &f[i]);        rep(i, 1, n) scanf("%d", &d[i]);        mep(i, 1, n) scanf("%d", &t[i]);        maxtime = 0;        cls(ans_time, 0);        rep(i, 1, n){ //枚举一下走过的湖泊数            int tmpsum = 0, sum = 0;            mep(j, 1, i){                sum += t[j]*5;            }            fishtime = (h * 60 - sum) / 5; //剩下的捕鱼时间,这里面可以瞬间转移            int curf[30], cur_ans_time[30];            cls(cur_ans_time, 0);            rep(j, 1, i) curf[j] = f[j];            rep(j, 1, fishtime){                int mxpos = 1;                rep(k, 1, i){ //可以堆优化                    if(curf[k] > curf[mxpos]){                        mxpos = k;                    }                }                tmpsum += curf[mxpos];                curf[mxpos] -= d[mxpos];                if(curf[mxpos] < 0){                    curf[mxpos] = 0;                }                cur_ans_time[mxpos] += 5;            }            if(tmpsum > maxtime){                rep(i, 1, n){                    ans_time[i] = cur_ans_time[i];                }                maxtime = tmpsum;            }        }        printf("Case %d:\n", ++ks);        printf("%d", ans_time[1]);        rep(i, 2, n){            printf(", %d", ans_time[i]);        }        printf("\n");        printf("Number of fish expected: %d\n", maxtime);    }    return 0;}

解题方法2: 除了贪心,还可以DP。。是wannafly菊苣的解法,设dp[i][j]表示i开始剩余时间是j的最大捕鱼量
每次枚举第i个湖上的钓鱼时间k,有dp[i][j] = max(dp[i - 1][j - k] + cost[i][k]), cost表示第i个湖捕k时间鱼的收获

贴一下大神给出的代码,来研究一下:

http://paste.ubuntu.com/23851847/

0 0
原创粉丝点击