uva11367 - Full Tank? 最短路 DP

通过分析欧洲之旅中各城市的汽油价格变化,本文提供了一个程序解决方案,帮助游客在下一次旅行中更聪明地选择加油地点以节省开支。文章详细介绍了如何构建新图并应用迪杰斯特拉算法来计算从出发点到目的地的最低油费路径。
  F: Full Tank? 

After going through the receipts from your car trip through Europe this summer, you realised that the gas prices varied between the cities you visited. Maybe you could have saved some money if you were a bit more clever about where you filled your fuel?

\epsfbox{p11367.eps}

To help other tourists (and save money yourself next time), you want to write a program for finding the cheapest way to travel between cities, filling your tank on the way. We assume that all cars use one unit of fuel per unit of distance, and start with an empty gas tank.

Input 

The first line of input gives 1$ \le$n$ \le$1000 and 0$ \le$m$ \le$10000 , the number of cities and roads. Then follows a line with n integers 1$ \le$pi$ \le$100 , where pi is the fuel price in the i th city. Then follow m lines with three integers 0$ \le$u , v < n and 1$ \le$d$ \le$100 , telling that there is a road between u and v with length d . Then comes a line with the number 1$ \le$q$ \le$100 , giving the number of queries, and q lines with three integers 1$ \le$c$ \le$100 , s and e , where c is the fuel capacity of the vehicle, s is the starting city, and e is the goal.

Output 

For each query, output the price of the cheapest trip from s to e using a car with the given capacity, or ``impossible" if there is no way of getting from s to e with the given car.

Sample Input 

5 5 
10 10 20 12 13 
0 1 9 
0 2 8 
1 2 1 
1 3 11 
2 3 7 
2 
10 0 3 
20 1 4

Sample Output 

170 
impossible

 

 

  N个点M条无向边,给你每个点的油价。Q个询问,每次询问给你油箱容量和起点终点,一单位距离花一单位油,问起点到终点最少花多少钱,不能到达输出-1。

  类似于以前马里奥那个,思路是把(u,fuel)当成一个点,就是一个二维的,在某个位置有多少油量这样一个状态当成一个点,用dijkstra,根据条件判断当前点连接的点(加一单位油或者花费油走到另一个位置,油要一单位一单位加,节省时间)。一旦到达终点就返回。

  这种题的思路是把原来的图根据二维关系状态转移的情况构成一个新图,求最短路。优先队列的dijkstra复杂度MlogN。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<queue>
#include<map>
using namespace std;

typedef pair<int,int> pii;

const int MAXN=1010;
const int MAXM=25;
const int MAXC=110;
const int MAXNODE=100010;
const int LOGMAXN=50;
const int INF=0x3f3f3f3f;

int N,M,Q,S,E,C;
int p[MAXN];

struct Point{
    int u,fuel,d;
    bool operator < (const Point& rhs) const{
        return d>rhs.d;
    }
};
struct Edge{
    int u,v,dist;
};

struct Dijkstra{
    int n;
    int d[MAXN][MAXC],vis[MAXN][MAXC];
    vector<int> G[MAXN];
    vector<Edge> edges;

    void init(int n){
        this->n=n;
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }
    void add_edge(int u,int v,int dist){
        edges.push_back((Edge){u,v,dist});
        int m=edges.size()-1;
        G[u].push_back(m);
    }
    int dijkstra(int S,int E,int C){
        priority_queue<Point> q;
        memset(d,INF,sizeof(d));
        memset(vis,0,sizeof(vis));
        d[S][0]=0;
        q.push((Point){S,0,0});
        while(!q.empty()){
            Point tmp=q.top();
            q.pop();
            int u=tmp.u,fuel=tmp.fuel;
            if(u==E) return d[u][fuel];
            if(vis[u][fuel]) continue;
            vis[u][fuel]=1;
            if(fuel<C&&d[u][fuel]+p[u]<d[u][fuel+1]){
                d[u][fuel+1]=d[u][fuel]+p[u];
                q.push((Point){u,fuel+1,d[u][fuel+1]});
            }
            int len=G[u].size();
            for(int i=0;i<len;i++){
                Edge& e=edges[G[u][i]];
                if(fuel>=e.dist&&d[u][fuel]<d[e.v][fuel-e.dist]){
                    d[e.v][fuel-e.dist]=d[u][fuel];
                    q.push((Point){e.v,fuel-e.dist,d[e.v][fuel-e.dist]});
                }
            }
        }
        return -1;
    }
}solver;

int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M)!=EOF){
        for(int i=0;i<N;i++) scanf("%d",&p[i]);
        solver.init(N);
        int u,v,dist;
        for(int i=0;i<M;i++){
            scanf("%d%d%d",&u,&v,&dist);
            solver.add_edge(u,v,dist);
            solver.add_edge(v,u,dist);
        }
        scanf("%d",&Q);
        while(Q--){
            scanf("%d%d%d",&C,&S,&E);
            int ans=solver.dijkstra(S,E,C);
            if(ans==-1) printf("impossible\n");
            else printf("%d\n",ans);
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值