hdu 3810 Magina 5亿的背包,队列优化DP

Magina

Time Limit: 60000/30000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 663    Accepted Submission(s): 212


Problem Description
Magina, also known as Anti-Mage, is a very cool hero in DotA (Defense of the Ancient).

If you have no idea of him, here is some brief introduction of his legendary antecedents:
Twin sons to the great Prophet, Terrorblade and Magina were blessed with divine powers: Terrorblade granted with an unnatural affinity with life forces; Magina gifted with energy manipulation. Magina's eventual overexposure to the magic gradually augmented his elemental resistances and bestowed him the unique ability to move faster than light itself. Now, broken by Terrorblade's fall to the dark side, Magina answers the Sentinel's call in a desperate bid to redeem his brother. Every bitter strike turns the Scourge's evil essences upon themselves, culminating in a finale that forces his enemy to awaken to the void within and spontaneously implode.
Magina has a very IMBA (imbalanced) skill – Blink, yes, move from one place to another place in a wink. Our problem begins at there.
As a formidable hero in the later stage, Magina always farm with the wild monsters for a long time. To make the farming more efficient, Magina use Blink frequently to jump here and there. Here we assume Blink skill has no CD, that is, we can use this skill at any time we want.
There are N spots of the wild monsters, and Magina can choose any one to begin. For every spots, Magina may use Ti time to kill the monsters and gain Gi units money, or he choose blink to other spots, which is known to our brilliant Magina. If the monsters in a spot were killed, it won’t appear any more.
Now Magina want to get M units money to but some excellent equipment, say Battle Fury for example. As a hero to save the world, there is no much time left for Magina, he wonders the minimum time for him to gain at least M units money.
 

Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with two integers N, M. Their meanings are the same as the description.
Then N blocks follow, each one describes a spot of wild monsters.
The first line of each block is there integers Ti, Gi and Ki. Ti is the time, Gi is the units of money, Ki is the number of spots Magina can blink to from here.
Then Ki integer Cij follow, indicating the spots’ ID Magina can blink to. You may assume no ID would appear twice.
The spots are described with ID increasing from 1 to N. Input ensure if you can blink from i to j, you can also blink from j to i.

Technical Specification

1. 1 <= T <= 50
2. 1 <= N <= 50
3. 1 <= Ti <= 10000000
4. 1 <= M, Gi <= 1000000000
5. 1 <= Ki < N
6. 1 <= Cij <= N
 

Output
For each test case, output the case number first, then the minimum time for Magina to gain at least M units money, if can’t, output “ Poor Magina, you can't save the world all the time!”.
 

Sample Input
  
  
3 1 4 2 5 0 1 5 1 4 0 4 10 1 9 0 3 3 1 3 3 3 2 2 4 4 4 1 3
 

Sample Output
  
  
Case 1: 2 Case 2: Poor Magina, you can't save the world all the time! Case 3: 10
 

Author
iSea@WHU
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   3816  3809  3811  3812  3815 
 


优先队列优化:

维护两个优先队列,
分阶段动归,
每次考虑第i个的物品时
队列1取出元素代表前i-1个物品时的情况,
按照从花费小的情况开始取,
所以然后新花费cost=花费oldcost+cost[i],新价值val=价值oldval+val[i],
 
1)如果val>=目标所需价值,不用放入队列2,只用将cost去更新ans的最小值即可。

 2)如果后取出val2<=val1,那么val2不用放入队列2。
因为cost2>=cost1。

3)否则将<cost,val>放入队列2,且按cost从小到大排序。

每次考虑完一个物品之后,对队列2中的元素进行筛选,此时队列1已经空了,没有被淘汰的元素放入队列1。

从cost较小的元素开始取,如果cost1<=cost2&&val2<=val1,那么物品2淘汰。

反复循环,直至结束。



/**==========================================
 *   This is a solution for ACM/ICPC problem
 *
 *   @source:hdu 3810 Magina
 *   @type:  dp
 *   @author: wust_ysk
 *   @blog:  http://blog.csdn.net/yskyskyer123
 *   @email: 2530094312@qq.com
 *===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
#include<climits>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 50   ;
int n,des;
int cost[maxn+5],val[maxn+5];
vector<int >G[maxn+5];
vector<int >ve;
bool vis[maxn+5];
struct Node
{
    int v,val;
    Node(){}
    Node(int v,int val):v(v),val(val){}
    bool operator<(const Node & y)const
    {
        if(v!=y.v)  return v>y.v;
        return   val<y.val;
    }

};
int ans ;

void init()
{
    ans=INT_MAX;
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)  G[i].clear();

}

void dfs(int x)
{
    ve.push_back(x);
    for(int i=0;i<G[x].size();i++)
    {
        int y=G[x][i];if(vis[y])  continue;
        vis[y]=1;
        dfs(y);
    }

}

void DP()
{
    priority_queue<Node>  q[2];
    int now=0,nex=1;
    q[now].push( Node(0,0) );

    for(int i=0;i<ve.size();i++ )
    {
        int x=ve[i];int maxi=0;
        while(!q[now].empty())
        {
            Node  y=q[now].top();q[now].pop();
            int   v=y.v;
            int tval=y.val;
            q[nex].push(y);

            int v2=v+cost[x];
            int tval2=tval+val[x];

            if(tval2>=des)
            {
                ans=min( v2,ans);
                continue;
            }
            if(tval2<=maxi)
            {
                continue;
            }
            maxi=tval2;
            q[nex].push(Node(v2,tval2));
        }
        maxi=-1;//如果这里maxi=0,底下的判断必须用if(x.val<maxi) 否则Node(0,0)会被剃掉
        while(!q[nex].empty())
        {
            Node x=q[nex].top();q[nex].pop();
            if(x.val<=maxi)  continue;
            q[now].push(x);
            maxi=x.val;
        }

    }
}
void work()
{
      for(int i=1;i<=n;i++)  if(!vis[i])
      {
          vis[i]=1;
          ve.clear();
          dfs(i);
          DP();
      }

}
int main()
{
    int T;int x,y,k,kase=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&des);
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&cost[i],&val[i],&k);
            for(int j=1;j<=k;j++)
            {
                scanf("%d",&x);
                G[i].push_back(x);
            }
        }
        work();
        printf("Case %d: ",++kase);
        if(ans!=INT_MAX)  printf("%d\n",ans);
        else puts("Poor Magina, you can't save the world all the time!");
    }


   return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值