ybt1373 鱼塘钓鱼
时空限制 1000ms/64MB
【题目描述】
有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,例如:N=5时,如下表:
即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,……
给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。
假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。
【输入】
共5行,分别表示:
第1行为N;
第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;
第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;
第4行为当前鱼塘到下一个相邻鱼塘需要的时间;
第5行为截止时间T。
【输出】
一个整数(不超过231−1
),表示你的方案能钓到的最多的鱼。
【输入样例】
5 10 14 20 16 9 2 4 6 5 3 3 5 4 4 14
【输出样例】
76
代码
法一:贪心
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 105;
int n,f[N],d[N],t[N],T;
int a[N],ans;
int main(){
cin>>n;
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; i++) cin>>t[i];
cin>>T;
for (int i=1; i<=n; i++){ //枚举终点鱼塘
for (int j=1; j<=i; j++) a[j]=f[j]; //初始化
T -= t[i-1]; // T 鱼塘1-i所剩钓鱼时间
int tot=0;
for (int j=1; j<=T; j++){
int pos=0;
for (int k=1; k<=i; k++) //每次钓鱼在哪个鱼塘
if (a[k]>a[pos]) pos=k;
if (pos==0) break; //所有鱼塘都钓不了鱼
tot += a[pos]; //累加本次钓鱼数
a[pos] -= d[pos]; //本次鱼塘下次钓鱼数
}
ans = max(ans,tot);
}
cout<<ans<<endl;
return 0;
}
法二:STL优先队列
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 105;
struct node{
int fish,id;
bool operator < (const node &x)const{
return fish<x.fish; //重载 < 成大根堆
}
}f[N];
priority_queue<node> pq;
int n,d[N],t[N],T,ans;
int main(){
cin>>n;
for (int i=1; i<=n; i++){
cin>>f[i].fish;
f[i].id=i; //鱼塘编号
}
for (int i=1; i<=n; i++) cin>>d[i];
for (int i=1; i<n; i++) cin>>t[i];
cin>>T;
for (int i=1; i<=n; i++){ //枚举终点鱼塘
while (!pq.empty()) pq.pop(); //清空堆
for (int j=1; j<=i; j++) pq.push(f[j]); //建大顶堆
T -= t[i-1]; // T 鱼塘1-i所剩钓鱼时间
int tot=0;
for (int j=1; j<=T; j++){
node x=pq.top(); pq.pop(); //取出最大值
if (x.fish<=0) break;
tot+=x.fish; //累加本次钓鱼数
x.fish -= d[x.id]; //本次鱼塘下次钓鱼数
pq.push(x); //重新入堆
}
ans = max(ans,tot);
}
cout<<ans<<endl;
return 0;
}
法三:手动堆
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 105;
struct node{
int fish,id;
}heap[N];
int n,f[N],d[N],t[N],T,ans;
void adjust(int i,int m){
for (int j=2*i; j<=m; ){
if (j<m && heap[j+1].fish>heap[j].fish) j++; //存在右孩子且值大
if (heap[i].fish<heap[j].fish){ //heap[i]父亲节点 heap[j]孩子节点
swap(heap[i],heap[j]);
i = j;
j = 2*i;
}
else break;
}
}
int main(){
cin>>n;
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; i++) cin>>t[i];
cin>>T;
for (int i=1; i<=n; i++){ //枚举终点鱼塘
for (int j=1; j<=i; j++){ //建立大顶推
heap[j].fish = f[j];
heap[j].id = j;
}
for (int j=i/2; j>=1; j--) adjust(j,i);
T -= t[i-1]; // T 鱼塘1-i所剩钓鱼时间
int tot=0;
for (int j=1; j<=T; j++){
if (heap[1].fish<=0) break;
tot += heap[1].fish; //累加本次钓鱼数
heap[1].fish -= d[heap[1].id]; //本次鱼塘下次钓鱼数
adjust(1,i); //向下调整
}
ans = max(ans,tot);
}
cout<<ans<<endl;
return 0;
}