题意:
出一些独立的陆地,每片陆地上有非常多怪物。杀掉每一个怪物都须要一定的时间,并能获得一定的金钱。给出指定的金钱m, 求最少要多少时间能够得到m金钱,仅能选择一个陆地进行杀怪。
题解:
这题,假设无论数据范围,非常easy想到对每片陆地求一次0-1背包(dp(i, j) = min(dp(i-1, j), dp[i-1, j-money] + time), i 为金钱)。然后在全部陆地中找出最少的时间即为答案,可是这题的数据范围太大金钱m可达到1e9, 所以不能单纯的直接用数组模拟,考虑第i个怪物,要更新第i个怪物。仅仅须要知道两个状态,那就是dp[i-1][j], 和dp[i-1][j-money]。 所以。我们仅仅须要保存第i-1个怪物的所有合法状态,就能更新第i个怪物的状态。 所以我们能够考虑使用两个优先队列来维护上一轮的状态和这一轮的状态。就能找到答案了。首先,将两个队列都依照money从大到小。time从小到大的顺序排列,每次把q1所有出队列更新下一个状态,并把两个状态都放入q2中,然后从q2中选择最优解再拷贝到q1中,最后更新ans就可以。
代码:
#include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; typedef long long LL; typedef vector<int>::iterator Pointer; const int maxn = 60; const int inf = 1e9; vector<int> group[maxn]; vector<int> mp[maxn]; int n, m, gcnt; struct node { LL tm, val; node() {} node(LL tm, LL val) : tm(tm), val(val) {} bool operator < (const node& tmp) const { return val < tmp.val || (val == tmp.val && tm > tmp.tm); } }arr[maxn], now, nxt; void init() { for (int i = 0; i < maxn; ++i) group[i].clear(), mp[i].clear(); } bool vis[maxn]; void dfs(int u) { group[gcnt].push_back(u); vis[u] = true; for (Pointer it = mp[u].begin(); it != mp[u].end(); ++it) { int v = *it; if (!vis[v]) { dfs(v); } } } void divide_group() { memset(vis, false, sizeof vis); gcnt = 0; for (int i = 1; i <= n; i++) { if (!vis[i]) { dfs(i); gcnt++; } } } priority_queue<node> q1, q2; inline void clear_queue() { while (!q1.empty()) { q1.pop(); } while (!q2.empty()) { q2.pop(); } } LL mint; void zeroOnePack(int team) { for (Pointer it = group[team].begin(); it != group[team].end(); ++it) { int v = *it; while (!q1.empty()) { now = q1.top(), q1.pop(); q2.push(now); nxt = node(now.tm+arr[v].tm, now.val+arr[v].val); if (nxt.val >= m && nxt.tm < mint) { mint = nxt.tm; continue; } if (nxt.tm >= mint) continue; q2.push(nxt); } LL pre = inf; while (!q2.empty()) { node tmp = q2.top(); q2.pop(); if (tmp.tm < pre) { pre = tmp.tm; q1.push(tmp); } } } } LL solve() { mint = inf; for (int i = 0; i < gcnt; i++) { now = node(0, 0); clear_queue(); q1.push(now); zeroOnePack(i); } return mint == inf ?-1 : mint; } int main() { // freopen("/Users/apple/Desktop/in.txt", "r", stdin); int t, kase = 0; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); init(); for (int i = 1; i <= n; i++) { int k; scanf("%lld%lld%d", &arr[i].tm, &arr[i].val, &k); for (int j = 0; j < k; j++) { int v; scanf("%d", &v); mp[i].push_back(v); } } divide_group(); LL ans = solve(); printf("Case %d: ", ++kase); if (ans == -1) { printf("Poor Magina, you can't save the world all the time! "); } else { printf("%lld ", ans); } } return 0; }