hdu 3810 Magina 队列模拟0-1背包
来源:互联网 发布:网络黄金最新消息 编辑:程序博客网 时间:2024/04/27 13:52
题意:
出一些独立的陆地,每片陆地上有很多怪物,杀掉每个怪物都需要一定的时间,并能获得一定的金钱,给出指定的金钱m, 求最少要多少时间可以得到m金钱,仅能选择一个陆地进行杀怪。
题解:
这题,如果不管数据范围,很容易想到对每片陆地求一次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!\n"); } else { printf("%lld\n", ans); } } return 0;}
0 0
- hdu 3810 Magina 队列模拟0-1背包
- hdu 3810 Magina 队列优化的0-1背包t
- HDU 3810 Magina (推荐)搜索+队列模拟背包
- hdu 3810 Magina 搜索+队列模拟分组背包
- hdu 3810 Magina 5亿的背包,队列优化DP
- HDU3810 Magina(搜索+用优先队列模拟01背包)经典
- HDU 3810 Magina
- Magina HDU
- HDU 3810 Magina 题解(搜索)
- hdu 1972 队列模拟
- HDU 5410 (0 1背包+ 完全背包)
- HDU 5437--优先队列模拟
- HDU-5437-模拟-优先队列
- HDU 6136 模拟 + 优先队列
- HDU 6136 优先队列 模拟
- hdu 6136 模拟+优先队列
- hdu 6168 模拟+优先队列
- hdu 5437 优先队列 模拟
- crontab的格式
- 通过重写ViewGroup学习onMeasure()和onLayout()方法
- 数据库(MSSQLServer,Oracle,DB2,MySql)常见语句以及问题(续1之拼接字符串)
- bhkjbhigigbikbgfuvovbi
- ffasdfas
- hdu 3810 Magina 队列模拟0-1背包
- Android中onMesure研究
- NumPy for MATLAB users
- 【数据结构】图结构的创建和遍历算法
- Core Data的使用(一)
- robots.txt
- sql的transaction用法
- JavaScript的闭包问题(闭包解决引用循环变量的问题)
- 冒泡排序(1)