POJ3635 装满的油箱 :优先队列BFS +链式向前星

原题连接
POJ3635
  这道题是给定一张城市之间有权无向图,每个城市都有加油站,但是每个加油站价钱不一样,对于多次询问,给定两城市和油缸容量,问最少花费。
  思路:对于最短或最少问题,可以用BFS解决,但是这道题并不是求最短路径,需要结合优先队列进行变形。
  可以用结构体+数组表示状态,当前所在城市、当前油量以及花费
  对于每个城市,有两种分支选择
  1)在这个城市加一升油,之所以选择加一升,是寻找最优解,并将当前状态加入优先队列。这里的一升并不是只在当前城市加一升油,因为已将当前状态置入队列,当其是最优,或者从队列中弹出时还可以继续进行加油操作。
  2)通过链式向前星寻找当前城市可继续行驶的城市(油量充足、连通)。
  因为是优先队列大大减少了不必要的循环。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define N 1001
#define M 10100
using namespace std;
int n,m,s,t,c;
int head[N],next[2*M],ver[2*M],cost[2*M],tot=-1;
int fuel[N];
int ans[N][102];
bool vis[N][102];
void add(int x,int y,int val){
    cost[++tot]=val;
    ver[tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
struct Node
{
    int u,f,w;//u当前城市、f剩余油量、w当前花费
    Node(int a,int b,int c):u(a),f(b),w(c){}
    friend bool operator < (Node a,Node b){
        return  a.w>b.w;
    }
};
priority_queue <Node> q;
bool test1(int u,int f){
    if(!vis[u][f+1]&&f+1<=c&&(ans[u][f+1]>ans[u][f]+fuel[u]))
        return 1;
    return 0;
}
bool test2(int v,int f,int p,int w){
    if(f>=p && !vis[v][f-p] && ans[v][f-p]>w)
        return 1;
    return 0;
}
int bfs(){
    memset(ans,0x3f,sizeof(ans));
    memset(vis,false,sizeof(vis));
    while(!q.empty()) q.pop();
    ans[s][0]=0;
    Node now1(s,0,0);
    q.push(now1);
    while(!q.empty()){
        Node now=q.top();q.pop();
        int u=now.u;
        int f=now.f;
        int w=now.w;
        vis[u][f]=true;
        if(u==t) return w;
        if(test1(u,f)){
            ans[u][f+1]=ans[u][f]+fuel[u];
            q.push(Node(u,f+1,ans[u][f+1]));
        }
        for(int i=head[u];i;i=next[i]){
            int y=ver[i];
            int spend=cost[i];
            if(test2(y,f,spend,w)){
                ans[y][f-spend]=w;
                q.push(Node(y,f-spend,w));
            }
        }
    }
    return -1;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>fuel[i];
    }
    for(int i=1;i<=m;i++){
        int x,y,z;
        cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
    }
    int num;
    cin>>num;
    while(num--){
        cin>>c>>s>>t;
        int anss=bfs();
        if(anss==-1)
            printf("impossible\n");
        else
            printf("%d\n",anss);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值