【POJ3635】Full Tank 优先队列BFS

普通BFS:每个状态只访问一次,第一次入队时即为该状态对应的最优解。
优先队列BFS:每个状态可能被更新多次,入队多次,但是只会扩展一次,每次出队时即为改状态对应的最优解。
且对于优先队列BFS来说,每次存入队列的不光是像普通BFS的状态,还有当前状态对应的代价,并且是依据最小代价进行扩展。每次状态被更近之后,将其入队。

对于本题来说
状态选取:当前所在城市,当前油量
代价函数:当前状态所对应的最小花费

代码如下:

#include <cstdio>
#include <iostream>
#include <utility>
#include <algorithm>
#include <queue>
#include <memory.h>
#define cls(a,b) memset(a,b,sizeof(a))
using namespace std;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

int d[1001][101],cost[1001];
bool vis[1001][101];
int n,m,q;
int c,st,ed;
struct edge{
    int to,w;
    edge(int to=0,int w=0):to(to),w(w){}
};
vector<edge> G[1001];
inline void add_edge(int from,int to,int w){
    G[from].push_back(edge(to,w));
    G[to].push_back(edge(from,w));
}

int bfs(){
    priority_queue< pair<int,pair<int,int> > > q;//存代价和状态
    cls(vis,0);cls(d,0x3f);
    d[st][0]=0;q.push(make_pair(0,make_pair(st,0)));
    while(q.size()){
        int city=q.top().second.first,fuel=q.top().second.second;q.pop();
        if(vis[city][fuel])continue;//每个状态只会被扩展一次

        if(city==ed)return d[city][fuel];//每个状态出队扩展时,对应最优解

        vis[city][fuel]=1;//记录状态是否被扩展

        if(fuel<c&&d[city][fuel+1]>d[city][fuel]+cost[city]){//满足条件,并且可以更新最优解
            d[city][fuel+1]=d[city][fuel]+cost[city];
            q.push(make_pair(-d[city][fuel+1],make_pair(city,fuel+1)));
        }
        for(int i=0;i<G[city].size();i++){
            int to=G[city][i].to,w=G[city][i].w;
            if(fuel>=w&&d[to][fuel-w]>d[city][fuel]){
                d[to][fuel-w]=d[city][fuel];
                q.push(make_pair(-d[to][fuel-w],make_pair(to,fuel-w)));//负号为改大根堆为小根堆
            }
        }
    }
    return -1;
}

void read_and_parse(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)cost[i]=read();
    for(int i=1;i<=m;i++){
        int from=read()+1,to=read()+1,w=read();
        add_edge(from,to,w);
    }
}

void solve(){
    q=read();
    while(q--){
        c=read(),st=read()+1,ed=read()+1;
        int ans=bfs();
        if(ans==-1)puts("impossible");
        else printf("%d\n",ans);
    }
}

int main(){
    read_and_parse();
    solve();
    return 0;
}

转载于:https://www.cnblogs.com/wzj-xhjbk/p/9800471.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ 3635 是一道比较经典的数学题目,主要考察了一些数学知识和算法。下面是这道题的 Java 解题思路和代码实现: 题目描述: 给定一个正整数N,求最小的正整数M,使得 N*M 的十进制表示中只包含数字0和1。 输入格式: 一个正整数N。 输出格式: 一个正整数M,表示满足条件的最小正整数M。 Java 代码实现: ```java import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); long n = sc.nextLong(); long res = 1; Queue<Long> queue = new LinkedList<>(); Set<Long> set = new HashSet<>(); queue.offer(1L); set.add(1L); while (!queue.isEmpty()) { long t = queue.poll(); if (t % n == 0) { res = t; break; } long a = (t * 10) % n; long b = (t * 10 + 1) % n; if (!set.contains(a)) { queue.offer(a); set.add(a); } if (!set.contains(b)) { queue.offer(b); set.add(b); } } System.out.println(res); } } ``` 思路解析: 这道题的解题思路比较巧妙,我们可以采用 BFS 算法来解决。我们可以从 1 开始进行 BFS,每次将当前的数乘以 10 或者乘以 10 再加上 1,得到两个新的数,然后判断这两个新的数是否是 n 的倍数,如果是,则找到了最小的满足条件的数,退出 BFS。如果不是,则将两个新的数加入队列,继续进行 BFS。需要注意的是,由于 N 可能非常大,所以我们需要使用 long 类型来存储数值,同时我们需要使用集合来避免重复计算。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值