Poj-1042-Gone Fishing-枚举+贪心

来源:互联网 发布:怎么申请淘宝旗舰店 编辑:程序博客网 时间:2024/05/19 15:19

题面:
John is going on a fishing trip. He has h hours available (1 <= h <= 16), and there are n lakes in the area (2 <= n <= 25) all reachable along a single, one-way road. John starts at lake 1, but he can finish at any lake he wants. He can only travel from one lake to the next one, but he does not have to stop at any lake unless he wishes to. For each i = 1,…,n - 1, the number of 5-minute intervals it takes to travel from lake i to lake i + 1 is denoted ti (0 < ti <=192). For example, t3 = 4 means that it takes 20 minutes to travel from lake 3 to lake 4. To help plan his fishing trip, John has gathered some information about the lakes. For each lake i, the number of fish expected to be caught in the initial 5 minutes, denoted fi( fi >= 0 ), is known. Each 5 minutes of fishing decreases the number of fish expected to be caught in the next 5-minute interval by a constant rate of di (di >= 0). If the number of fish expected to be caught in an interval is less than or equal to di , there will be no more fish left in the lake in the next interval. To simplify the planning, John assumes that no one else will be fishing at the lakes to affect the number of fish he expects to catch.
Write a program to help John plan his fishing trip to maximize the number of fish expected to be caught. The number of minutes spent at each lake must be a multiple of 5.
大意:
有n个湖,每个湖中有f[i]条鱼,每在一个湖钓5分钟的鱼,该湖鱼的数量就要减少d[i]。问给你h小时,最多能钓多少条鱼?在该情况下,在每个湖待的时间又是多少?
AC代码:

int n,h;//湖的个数、时间//鱼数、减少的数目、移动需要花费的时间,f的复制数组copy_f,最终在每个湖待的时间,每次(枚举)在每个湖待的时间int f[30],d[30],t[30],time_of_drive[30],copy_f[30],stay_time[30],stay_temp[30];bool compare(int a[],int b[])// 比较数组a是否大于b,这里忽略了相等的情况{    for(int i = 1; i <= n; ++i)    {        if(a[i] > b[i])            return true;        if(b[i] > a[i])            return false;    }}int main(){    int cases = 0;    while(true)    {        cin >> n;        if(n == 0)            break;        cin >> h;        for(int i = 1; i <= n; ++i)            cin >> f[i];        for(int i = 1; i <= n; ++i)            cin >> d[i];        for(int i = 1; i <= n - 1; ++i)            cin >> t[i];        memset(time_of_drive,0,sizeof(time_of_drive));//重置        if(cases != 0)//控制空行的输出            cout << endl;        cases++;        //枚举最后一个到达的湖,最后一个湖一定到达了,但不一定在其中钓过鱼        for(int i = 1; i <= n; ++i)            for(int j = 1; j <= i - 1; ++j)//此时花在路上的时间可以算出来                time_of_drive[i] += 5 * t[j];        int max_fish = -inf;//初始化最大鱼数        for(int i = 1; i <= n; ++i)//枚举最后一个到达的湖        {            for(int j = 1; j <= n; ++j)//复制一下f                copy_f[j] = f[j];            memset(stay_temp,0,sizeof(stay_temp));            //花在钓鱼上的时间            int copy_m = h * 60 - time_of_drive[i];//因为要多次用到时间,所以定义一个副本            int cnt = 0;//计算鱼的数量            while(copy_m > 0)//不停地瞬移(找出鱼最多的那个湖,然后瞬移)、钓鱼            {                //由于copy_m是5的倍数,故不用担心会出现死循环                //找出鱼最多的那个湖                //一下找湖的过程有点像单源最短路径dijkstra中找最近邻接点                //可以用优先队列来优化                int Max = -inf;                int m;                for(int j = 1; j <= i; ++j)                    if(copy_f[j] > Max)                    {                        Max = copy_f[j];//更新                        m = j;//记录                    }                if(copy_m >= 5)                {                    copy_m -= 5;//花时间                    stay_temp[m] += 5;//累加时间                    cnt += copy_f[m];//钓鱼                    if(copy_f[m] >= d[m])                        copy_f[m] -= d[m];//鱼数下降                    else                        copy_f[m] = 0;//但不能降成负数                }            }            if(cnt > max_fish)            {                max_fish = cnt;//更新                for(int j = 1; j <= n; ++j)                    stay_time[j] = stay_temp[j];//更新待的时间            }            else if(cnt == max_fish && compare(stay_temp,stay_time) == true)//根据题目要求            {                //答案相同就输出在第1个湖待的时间长的情况,再相同就输出在第2个湖待的时间长的情况,以此类推                for(int j = 1; j <= n; ++j)                    stay_time[j] = stay_temp[j];//更新待的时间            }        }        if(cases != 1)            cout << endl;        for(int j = 1; j <= n; ++j)//输出在每个湖待的时间        {            if(j != 1)                printf(", ");            cout << stay_time[j];        }        cout << endl;        printf("Number of fish expected: %d",max_fish);//输出最大鱼数    }    return 0;}

解决方法:
①通过分析样例得知,递减的规则是:举个例子,我在第一个湖,第一个5分钟钓10条,第2个5分钟钓5条。不可以想成时间每过5分钟每个湖中的鱼数就要减5条,这样一是不符合逻辑,二是大大增加了题目的复杂度。所以说能联想到做过的题目是好事,但是形成思维定式就是有害的了。通过以上可知,约翰只能向前走,也就是从第i个湖走向第i + 1个湖,如果有往返,就只能白白地浪费时间,把时间花在了路上。
②由以上可知,在钓鱼结束后,约翰可能在第1个湖待过,可能在第1个湖和第2个湖待过,可能在第1个湖、第2个湖和第3和湖待过……还可能在第1……n个湖待过。
由以上“待过”的说法可以看出,约翰有可能经过一个湖,但并未在其中钓鱼。
③此题的数据规模不大,所以可以通过暴力枚举的方法,枚举最后一个待过的湖的编号。
一般来说,模拟有助于程序的编写,但是在某些情况下,就要将题意进行等价转换,使得题目得到简化。比如在本题中,就是将钓鱼时间和花在路上的时间分开。有了以上的分析,花在路上的时间非常好求。
④转换题意,在上一个湖钓完了再去下一个湖钓就等价于在1-x之间可以两两瞬间移动,并且采用贪心策略,选择鱼数最多的湖,直到花完所有的时间。