POJ3635 Full Tank? - 优先队列BFS

题意:有N个城市M条双向道路,每个城市都有一个加油站和单位加油费用,每条边都有一个权值,经过这条边需要消耗油箱中边权数量的油。现在有Q组询问,每次给定油箱容量C、起点S和终点T,问从S到T的最小花费是多少,若无法到达输出“impossible”。

思路:

对于每次扩展都有各自不同代价时,求出从起始状态到每个状态的最小状态的问题,相当于在一张带权图上跑最短路。因此对于这类问题,有两种解决方案:

1、对搜索树进行重复遍历与更新,直至收敛到最优解,这用到了“迭代思想”,相当于SPFA,时间复杂度由O(n)到O(n^2)。

2、优先队列BFS,每次取出当前代价最小的状态进行扩展。根据广搜的单调性,对于一个状态,当第一次遍历到它时,即得到了到达这个状态的最优解。由于每个状态只扩展一次,所以优先队列BFS的时间复杂度是O(nlogn),相当于Dijkstra。

//------------以上内容来自 李煜东 神犇的著作  《算法竞赛进阶指南》-------------//

对于本题,相当于求从S到T的最短路。

这里有个小优化:对于每个状态,我们可以令其向自己转移一下,而不用把接下来所有的状态一次转移完。

例如本题,对于每个城市,若当前油箱中有rest单位的油,油箱容量为c,我们不必一次性将rest+1~c的状态加入队列,而可以将rest+1加入队列,这样终归会将所有状态遍历一遍,还省去了不少复杂操作。

还有就是vis数组判重时,最好在该状态从队列中取出时再标记,否则会漏掉部分状态。

P.S.对于impossible的情况,好像不需要并查集来维护连通性。。

AC Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1000+100,M=10000+100,C=100+100;
//邻接表 
struct node{
    int to,nxt,w;
}e[M<<1];
int head[N],tot;
void add(int u,int v,int w){
    e[++tot]=(node){v,head[u],w};
    head[u]=tot;
}
int p[N];//price
//并查集维护连通性 
int fa[N];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
//BFS  
struct poi{
    int vec,fuel,d;
};
//queue<poi>q;
priority_queue<poi>q;
bool operator < (const poi& a,const poi& b){
    return a.d>b.d;
}
bool vis[C][N];
int dis[C][N];
void BFS(int s,int t,int c){
    while(q.size()) q.pop();
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    q.push((poi){s,0,0});
    vis[0][s]=1;
    dis[0][s]=0;
    while(q.size()){
        poi tmp=q.top();q.pop();
        int u=tmp.vec,rest=tmp.fuel,dist=tmp.d;
        if(u==t) {
            printf("%d\n",dist);
            return ;    
        }
        vis[rest][u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(rest<c&&!vis[rest+1][u]&&dis[rest+1][u]>dist+p[u]){
                q.push((poi){u,rest+1,dist+p[u]});
                dis[rest+1][u]=dist+p[u];
            }
            if(rest>=e[i].w&&!vis[rest-e[i].w][v]&&dis[rest-e[i].w][v]>dist){
                q.push((poi){v,rest-e[i].w,dist});
                dis[rest-e[i].w][v]=dist;
            }
        }
    }
    printf("impossible\n");
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d",&p[i]);
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
        if(find(u)!=find(v)) fa[find(u)]=find(v);
    }
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int c,x,y;
        scanf("%d%d%d",&c,&x,&y);
        if(find(x)!=find(y)){
            printf("impossible\n");
            continue;
        }
        BFS(x,y,c);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9147976.html