标签:
题目链接: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