HDU - 4784(状态设计搜索)

因为数据较小,可以考虑搜索。

主要的维度为当前位置p,当前消耗时间t,当前持有的盐b,当前所在宇宙k。

最大状态数为100*200*5*6,如果直接用bfs爆搜,因为状态间的边权不是统一的1,那么bfs第一次更新到的点不一定是最优值,所以每个状态需要多次被更新,且多次进入队列,会超时。

但有了时间这一维度,就产生了不同,加入队列的节点,按t值小的先出队列,那么每个节点出来之后就不会被再更新,原因很简单,所有在队列里和被队列里节点更新的节点,在该节点出队列以后不可能更新到该节点。这样用一个队列即可。

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)
typedef long long ll;

const int NN = 115;
const int MM = 215;
struct node{
   int to,t,v;
   node(){}
   node(int to,int t,int v):to(to),t(t),v(v){}
};
vector<node> G[NN];
struct node2{
   int p,t,b,k;
   node2(){}
   node2(int p,int t,int b,int k):p(p),t(t),b(b),k(k){}
   bool operator<(const node2& rhs)const{
      return t > rhs.t;
   }
};
priority_queue<node2> Q;
int price[6][NN], N, M, B, K, R, T,d[NN][MM][6][6];
inline void update(node2 a,int v){
   if(v > d[a.p][a.t][a.b][a.k]){
       if(d[a.p][a.t][a.b][a.k] == -1) { Q.push(a);}
       d[a.p][a.t][a.b][a.k] = v;
   }
}
void bfs(){
   memset(d,-1,sizeof(d));
   d[1][0][0][0]=R;
   Q.push(node2(1,0,0,0));
   while(!Q.empty()){
       node2 u = Q.top(); Q.pop();
       int p = u.p, t=u.t, b=u.b,k=u.k;
       int now = d[p][t][b][k];
       if(p == N) continue;
       rep(i,G[p].size()){
           int p1 = G[p][i].to,cst=G[p][i].t,v=G[p][i].v;
           if(now - v <0 || t+cst > T) continue;
           if((p1 == 1 || p1 == N) && k!=0) continue;
           update(node2(p1,t+cst,b,k),now-v);
           if(p1 == 1 || p1 == N) continue;
           if(b < B) update(node2(p1,t+cst,b+1,k),now-v-price[k][p1]);
           if(b > 0) update(node2(p1,t+cst,b-1,k),now-v+price[k][p1]);
       }
       if(p == 1 || p == N) continue;
       int nk = (k+1)%K;
       if(t+1 > T) continue;
       update(node2(p,t+1,b,nk),now);
       if(b < B) update(node2(p,t+1,b+1,nk),now-price[nk][p]);
       if(b > 0) update(node2(p,t+1,b-1,nk),now+price[nk][p]);
   }
}
int main()
{
   int Ta,kase=1;
   scanf("%d",&Ta);
   while(Ta--){
      scanf("%d %d %d %d %d %d",&N, &M, &B, &K, &R, &T);
      rep(i,K) rep1(j,1,N) scanf("%d",&price[i][j]);
      rep1(i,1,N) G[i].clear();
      rep1(j,1,M){
         int x,y,t,v;
         scanf("%d %d %d %d",&x,&y,&t,&v);
         G[x].push_back(node(y,t,v));
      }
      printf("Case #%d: ",kase++);
      bfs();
      int ans = -1;
      rep1(i,1,T)
         if(ans < d[N][i][0][0])
              ans = d[N][i][0][0];
      if(ans == -1) printf("Forever Alone\n");
      else printf("%d\n",ans);
   }
   return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值