标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3810
题意:有n个地方有怪,杀死怪消耗时间得到金钱。在某些怪处可以瞬移到另一些怪处(双向),不花费时间。求取得金钱M的最小时间。
首先,这是一张无向图,可以看成若干个连通分量。敌法可以一个连通分量内任意移动,因为不消耗时间。
然后这题就变成了一个分组背包的问题。每个组内是一个背包问题,对于一个怪,你可以选择杀或不杀。如果数据正常,这题就可以A过了。
然而这题的数据不正常。背包的容量最大可以达到10亿,用普通的背包来做肯定不行。又发现怪的数量最多只有50。那么可以考虑用队列来模拟背包的过程,类似于离散化。
保存杀或者不杀怪的状态。其细节可以用滚动数组来实现,一个保存当前状态,一个保存更新后的状态。但这样最大的状态数依然有2^50那么多,依然不行。
背包九讲中讲过一个简单有效的优化
一个简单有效的优化
完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。
#include <iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #define INF 0x7ffffff #define N 55 using namespace std; struct node { int c,w; }p[N]; vector<node> group[N]; struct Node { int c,w;//c 时间,w 金钱 bool operator<(const Node a)const { return w!=a.w?w<a.w:c>a.c; //金钱从大到小,时间从小到大排列; } }s; int ans,cnt,v[N],n,m,mp[N][N]; void dfs(int c) { v[c]=1; group[cnt].push_back(p[c]); for(int i=1;i<=n;i++) if(!v[i]&&mp[c][i]) dfs(i); } void divid()//分组 { cnt=0; memset(v,0,sizeof(v)); for(int i=1;i<=n;i++) if(!v[i]) { group[cnt].clear(); dfs(i); cnt++; } } void slove() { ans=INF; priority_queue<Node> q1,q2; for(int i=0;i<cnt;i++)//对每组做背包 { while(!q1.empty()) q1.pop(); while(!q2.empty()) q2.pop(); s.c=s.w=0; q1.push(s); for(int j=0;j<group[i].size();j++) { while(!q1.empty())//对每个状态都考虑第j个物品取不取 { s=q1.top(); q1.pop(); q2.push(s); s.c+=group[i][j].c; s.w+=group[i][j].w; if(s.w>=m)//剪枝 { ans=min(ans,s.c); continue; } if(s.c>=ans) continue;//剪枝 q2.push(s); } int mincost=INF; while(!q2.empty())// 滚动数组 { s=q2.top(); q2.pop(); if(s.c<mincost)//更新状态+剪枝,将时间长且金钱少的状态去掉。 q1.push(s),mincost=s.c; } } } } int main() { int T,kase=0; cin>>T; while(T--) { cin>>n>>m; memset(mp,0,sizeof(mp)); for(int i=1;i<=n;i++) { int k; scanf("%d%d%d",&p[i].c,&p[i].w,&k); while(k--) { int t; scanf("%d",&t); mp[i][t]=mp[t][i]=1; } } divid(); slove(); printf("Case %d: ",++kase); if(ans==INF) printf("Poor Magina, you can't save the world all the time!\n"); else printf("%d\n",ans); } }
标签:
原文地址:http://blog.csdn.net/zchahaha/article/details/51336423