当前位置: 代码迷 >> 综合 >> hdu - 4600 - Harvest Moon
  详细解决方案

hdu - 4600 - Harvest Moon

热度:25   发布时间:2024-01-10 13:12:18.0

题意:农场游戏,一块w * h的土地,有A种种子可供选择但只可以选择一种,D天的种植时间,一个人有Y的钱。每种(x种)种子,一个种下,种下的格子及周围的8个格子N[x]天后有收获(重叠的格子只算1次),每个小格子卖出去可赚P[x]元,这种种子购入时每个Q[x]元,种子有些可以多次收获,有些不可以,可以多次收获的种子在第N[x]天第一次收获后每隔M[x]天收获一次。问D天后,这人的现金最多是多少(3 ≤ w, h ≤ 100, 0 <A, D ≤ 1000, 0 < Y ≤ 100000, 0 < Q_i, P_i ≤ 1000; N_i, M_i ≤ 10000)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4600

——>>传参时类型声明为了int,一直WA无数。。。

按天模拟(可能开始的时候,不够钱买更多的种子,以致有些空地没种子,于是有了收获有钱后并且再购买种子还有得赚则再购入种子)。

#include <cstdio>
#include <algorithm>
#include <cstring>using namespace std;const int maxn = 1000 + 10;
const int maxm = 9 + 5;int w, h, A, D;
long long Y;
int Q[maxn], P[maxn], N[maxn], M[maxn];
int num[maxm];      //num[i]表示9个格子中占了i个有效格子的种子数
int remain[maxm];       //remain[i]表示在种植了其中的一些种子后,剩余空地中9个格子中占了i个有效格子的种子数
int harvestGrid[maxn];      //harvestGrid[i]表示i天后有收获的土地格子数
int blank[maxn];        //blank[i]表示第i天有多少空地可以种植
int p;      //一个种子,尽量种在占格子尽量多的地方
int now;        //现在是第几天void read(){scanf("%d%d%d%d%I64d", &w, &h, &A, &D, &Y);for(int i = 1; i <= A; i++) scanf("%d%d%d%d", &Q[i], &P[i], &N[i], &M[i]);
}void init(){memset(num, 0, sizeof(num));num[9] = (w/3) * (h/3);     //左上方int ww = w % 3, hh = h % 3;num[9-(3-ww)*(3-hh)]++;     //右下角num[3*hh] += w/3 - 1;       //左下方num[3*ww] += h/3 - 1;       //右上角num[ww*hh] += 2;        //左下方与右下角中间的部分和右上角与右下角之间的部分
}bool isok(int x){       //判断这种种子是否值得购买if(!M[x]) return (long long)P[x] * p > Q[x] ? 1 : 0;      //时间要够,要能赚钱else return (long long)(1 + (D - now - N[x]) / M[x]) * p * P[x] > Q[x] ? 1 : 0;        //时间不够的话求出的是非正数,一样可以判
}long long work(int x, long long money){if(D - now < N[x]) return money;        //时间不够,直接返回while(p >= 1){if(!isok(x)){       //看看是否应该买种子p = 0;      //没有收获的话,不用再往下扫描,因为格子越少,赚得越少,下面的一定赚不了break;}//最终有收获,该买int numOfBuy = (remain[p] < money / Q[x]) ? remain[p] : money / Q[x];        //能买到的种子的个数remain[p] -= numOfBuy;      //剩余空地减少money -= Q[x] * numOfBuy;       //用去了一部分钱harvestGrid[now+N[x]] += numOfBuy * p;      //更新那些可以收获的日子blank[now+N[x]] += numOfBuy;        //那天会新空出numOfBuy的空地,是值得种植并且能够种植的(赚的钱比原来的成本更多了)(在时间允许下)if(!remain[p]) p--;else break;     //没钱了}return money;
}long long cal(int x){memset(harvestGrid, 0, sizeof(harvestGrid));        //初始时没种种子,哪一天都没有收获memcpy(remain, num, sizeof(num));       //初始时所有空地都没种种了,故remain == nummemset(blank, 0, sizeof(blank));        //初始化p = 9;now = 0;long long money = work(x, Y);        //第一次购买完种子后剩下的钱for(now = 1; now <= D; now++){      //模拟D天的收获if(!harvestGrid[now]) continue;money += harvestGrid[now] * P[x];      //可以收获的话if(!M[x] && D - now >= N[x]){       //在时间足够的前提下,将刚刚收获的土地继续种植money -= Q[x] * blank[now];       //用去了一部分钱harvestGrid[now+N[x]] += harvestGrid[now];      //更新那些可以收获的日子blank[now+N[x]] += blank[now];        //那天会新空出的空地,是值得种植并且能够种植的(赚的钱比原来的成本更多了)(在时间允许下)}else if(M[x] && D - now >= M[x]){        //在时间足够的前提下,将刚刚收获的土地继续收获harvestGrid[now+M[x]] += harvestGrid[now];      //更新那些可以收获的日子}money = work(x, money);}return money;
}void solve(){long long Max = -1;for(int i = 1; i <= A; i++) Max = max(Max, cal(i));printf("%I64d\n", Max);
}int main()
{int T;scanf("%d", &T);while(T--){read();init();solve();}return 0;
}