hdu4784 不错的搜索( 买卖盐,要求整钱最多)

题意:
      给你一个有向图,每个节点上都有一个盐价,然后给你k个空间,么个空间上节点与节点的距离不变,但盐价不同,对于每一个节点,有三种操作,卖一袋盐,买一袋盐 ,不交易,每一个节点可以跳掉(当前空间+1)%K的空间(特别注意,起点1和终点n不可以穿越),花费是时间1,金钱0 ,节点与节点之间都有花费时间和花费金钱,过程中金钱不可以是负数,问从节点1出发,在限制的时间内到达节点n的最大金钱数。


思路:

     这个题目做了将近两天,一开始写了各种深搜,各种超时,各种wa然后就开始各种广搜,写了很多版本,终于有一个能过的了,这个题目关键是就超时问题,说下思路,首先我们可以开一个数组mark[i][t][k][b] 表示的是第i个节点第t时刻,在第k层,有b袋盐的最大金钱数,然后就是搜索,写完了就是各种超时?为什么会超时,是因为我们进队出队次数太多,如果随意一算可能会这么想 可能会如认为进队次数是 N * T * K * B也就是mark的最大组合数,其实不然,对于同一个状态可能会进队多次,如果我们什么也不管,直接暴力,就是能更新就更新然后进队列,那么就会出现这么一种情况“当前这一步比之前的大了,我们直接更新进队,过了一会之后又来了一个,更新后的更大了,那么我们在更新进入队列”不要小看这两次进队,其实第一次进队我们所付出的代价是什么,代价是进队后更新后面的可更新的,等第二次进队了,再把后面的能更新的又更新了,这样的话,暴搜的代价就很大了,具体多大我算不明白,但妥妥保证你超时,就算你之前写一个逆向的最短路作为优化,照样超时(我试过很多种),那么该怎么办呢?其实对于每一个点,我们可以先把他的最优求出来,然后再去更新别人,因为是最优,所以这个点只会进队列一次,那怎么求最优呢?我们可以开个优先队列,就是把广搜的队列用优先队列,每次取出时间最小的,这样对于当前时间,比如是4,那么5这个时间点更新的时候<=4的肯定更新到最优了,所以这样每个点只要进队列一次就行了,优化了时间就可以ac了,如果你不满足于ac,还想更快,可以在写一个最短路去优化,反向存边,时间是权值,从终点跑一遍最短路,然后对于每一步来说,如果时间已经不能到终点了,那么当前终点就直接continue了。


#include<stdio.h>
#include<string.h>
#include<queue>

#define N_node 110
#define N_edge 220
#define INF 1000000000

using namespace std;

typedef struct
{
   int to ,next ,time ,money;
}STAR;

typedef struct NODE
{
   int nowt ,nowc ,nowy  ,id;
   friend bool operator < (NODE a ,NODE b)
   {
      return a.nowt < b.nowt;
   }
}NODE;

STAR E[N_edge];
NODE xin ,tou;
int list[N_node] ,tot;
int pic[6][N_node];
int mark[N_node][220][8][8];
int mk[N_node][220][8][8];
int N ,M ,B ,K ,R ,T ,Ans;

void add(int a ,int b ,int c ,int d)
{
   E[++tot].to = b;
   E[tot].time = c;
   E[tot].money = d;
   E[tot].next = list[a];
   list[a] = tot;
}

void BFS()
{
   memset(mark ,255 ,sizeof(mark));
   memset(mk ,0 ,sizeof(mk));
   xin.id = 1 ,xin.nowc = 0 ,xin.nowt = T ,xin.nowy = 0;
   priority_queue<NODE>q;
   q.push(xin);
   mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = R;
   mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
   while(!q.empty())
   {
      tou = q.top();
      q.pop();  
      if(tou.id == N)
      {
         if(Ans < mark[tou.id][tou.nowt][tou.nowc][tou.nowy])
         Ans =  mark[tou.id][tou.nowt][tou.nowc][tou.nowy];
         continue;
      }
      
      for(int k = list[tou.id] ; k ;k = E[k].next)
      {
         xin.id = E[k].to;
         xin.nowc = tou.nowc;
         xin.nowt = tou.nowt - E[k].time;
         int cost = mark[tou.id][tou.nowt][tou.nowc][tou.nowy] - E[k].money;
         if(xin.nowt < 0 || cost < 0) continue;
         if(xin.id == 1 && xin.nowc || xin.id == N && xin.nowc)
         continue;
         //不交易
         xin.nowy = tou.nowy;
         if(cost > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
         {
            mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost;
            if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy]) 
            {
               mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
               q.push(xin);
            }
         }
         if(xin.id == 1 || xin.id == N) continue;
         //买
         xin.nowy = tou.nowy + 1;
         if(xin.nowy <= B && cost - pic[xin.nowc][xin.id] >= 0)
         {
            if(cost - pic[xin.nowc][xin.id] > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
            {
               mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost - pic[xin.nowc][xin.id];
               if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy])
               {
                  mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
                  q.push(xin);
               }
            }
         } 
         //卖 
         xin.nowy = tou.nowy - 1;
         if(xin.nowy >= 0)
         {
            if(cost + pic[xin.nowc][xin.id] > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
            {
               mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost + pic[xin.nowc][xin.id];
               if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy])
               {
                  mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
                  q.push(xin);
               }
            }
         } 
      }
      
      if(tou.id == 1 || tou.id == N) continue;
      xin.id = tou.id;
      xin.nowc = (tou.nowc + 1) % K;
      xin.nowt = tou.nowt - 1;
      if(xin.nowt < 0) continue;
      int cost = mark[tou.id][tou.nowt][tou.nowc][tou.nowy];
      //不交易
      xin.nowy = tou.nowy;
      if(cost > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
      {
         mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost;
         if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy]) 
         {
            mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
            q.push(xin);
         }
      }
      //买
      xin.nowy = tou.nowy + 1;
      if(xin.nowy <= B && cost - pic[xin.nowc][xin.id] >= 0)
      {
         if(cost - pic[xin.nowc][xin.id] > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
         {
            mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost - pic[xin.nowc][xin.id];
            if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy])
            {
               mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
               q.push(xin);
            }
         }
      } 
      //卖 
      xin.nowy = tou.nowy - 1;
      if(xin.nowy >= 0)
      {
         if(cost + pic[xin.nowc][xin.id] > mark[xin.id][xin.nowt][xin.nowc][xin.nowy])
         {
            mark[xin.id][xin.nowt][xin.nowc][xin.nowy] = cost + pic[xin.nowc][xin.id];
            if(!mk[xin.id][xin.nowt][xin.nowc][xin.nowy])
            {
               mk[xin.id][xin.nowt][xin.nowc][xin.nowy] = 1;
               q.push(xin);
            }
         }
      } 
   }
}
  
      
int main ()
{
   int i ,j ,a ,b ,c ,d;
   int cas = 1 ,t;
   scanf("%d" ,&t);
   while(t--)
   {
      scanf("%d %d %d %d %d %d" ,&N ,&M ,&B ,&K ,&R ,&T);
      for(i = 0 ;i < K ;i ++)
      for(j = 1 ;j <= N ;j ++)
      scanf("%d" ,&pic[i][j]);
      memset(list ,0 ,sizeof(list)) ,tot = 1;
      for(i = 1 ;i <= M ;i ++)
      {
         scanf("%d %d %d %d" ,&a ,&b ,&c ,&d);
         add(a ,b ,c ,d);
      }
      Ans = -1;
      BFS();
      printf("Case #%d: " ,cas ++);
      Ans == -1 ? puts("Forever Alone"):printf("%d\n" ,Ans);
   }
   return 0;
}       
       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值