这道题没得说真的特别经典,枚举+贪心经典题目:首先lake数很少,故可以枚举出john最终停留在每个lake的钓鱼数。确定了john最终停留的lake数后,就可以利用贪心算法每次钓最多的鱼,注意:虽然lake是单线单行,但这并不影响每次取最大,因为实际中依次钓每个湖即可,这种抽象意义上 的贪心策略不好想,因此真的很经典!很经典!(重要的事说三遍)。
通过这道题真的可以学到很多知识,总结如下:
采用优先队列可以每次找到最大的钓鱼数,学习了一下priority_queue,以及利用cmp修改排序规则,注意优先队列默认是最大堆。
PE了好几次,纠结了好久才发现是由于结果最后多输出了一个空行。
还CE了一次。。。是由于提交到oj上时定义了一个非法的数组time[30],貌似这里time是保留字,但是我在dev上却编译通过了。
题目要求在有多种可能的情况下要在尽量靠前的位置停留,所以在重载排序规则时要注意lake要从小到大
#include <stdio.h>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
int n=1,h,lake[30],ti[30],fish[30],di[30];
struct Node{
int lable,fishNum;
Node (int a=0,int b=0):
lable(a),fishNum(b){}
};
struct loadcmp{
bool operator()(Node a,Node b){
if(a.fishNum == b.fishNum) return a.lable > b.lable;
return a.fishNum < b.fishNum;
}
};
int fishing(int last)
{
int times = h*12; int result = 0;
memset(lake,0,sizeof(lake));
for(int i=0;i<last;i++) times-=ti[i];
priority_queue<Node,vector<Node>,loadcmp> que;
for(int i=0;i<=last;i++){
if(fish[i]>0){
que.push(Node(i,fish[i]));
}
}
Node node;
while(times>0)
{
if(que.empty()) break;
times--;
node = que.top();
que.pop();
result+=node.fishNum;
node.fishNum-=di[node.lable];
if(node.fishNum>0) que.push(node);
lake[node.lable]++;
}
return result;
}
int main()
{
int flag=0;
while(scanf("%d",&n)&& n)
{
if(flag)
printf("\n");
flag++;
scanf("%d",&h);
for(int i=0;i<n;i++)
scanf("%d",&fish[i]);
for(int i=0;i<n;i++)
scanf("%d",&di[i]);
for(int i=0;i<n-1;i++)
scanf("%d",&ti[i]);
int fishMax = 0,lake_count=0,current_fish;
for(int i=0;i<n;i++){
current_fish = fishing(i);
if(current_fish > fishMax)
{fishMax=current_fish;lake_count=i;}
}
int sum=0;
fishing(lake_count);
for(int i=0;i<n;i++)
sum+=lake[i]*5;
for(int i=0;i<lake_count;i++)
sum+=ti[i]*5;
sum= h*60-sum;
cout<<lake[0]*5+sum;
for(int i=1;i<n;i++)
cout<<", "<<lake[i]*5;
//printf("\nNumber of fish expected: %d\n",fishMax);
cout<<'\n'<<"Number of fish expected: "<<fishMax<<endl;
}
return 0;
}