1. 程式人生 > >poj 3635 Full Tank? 圖上dp

poj 3635 Full Tank? 圖上dp

Description

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?

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 ≤ n ≤ 1000 and 0 ≤ m ≤ 10000, the number of cities and roads. Then follows a line with n integers 1 ≤ pi ≤ 100, where pi is the fuel price in the ith city. Then follow m lines with three integers 0 ≤ u, v < n and 1 ≤ d ≤ 100, telling that there is a road between u and v with length d. Then comes a line with the number 1 ≤ q ≤ 100, giving the number of queries, and q lines with three integers 1 ≤ c ≤ 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

題意:

已知每個點的加油站的油價單價(即點權),每條路的長度(邊權)。

有q個詢問,每個詢問包括起點s、終點e和油箱容量。

問從起點走到終點的最小花費。如果不可達輸出impossible,否則輸出最小的旅途費用。

演算法:

最直接的想法是 每到一個點都加上要走到下一個點所需要的油量。但是走的路不同,到底怎麼處理加多少的問題呢?

因此想到分解狀態,即拆點。每到一個點都+1單位的油量,然後把這個狀態加入佇列。另外如果現在油箱內的油足夠達到下一點,

則更新狀態,把新狀態加入優先佇列。

dp[i][j]表示到第i個城市剩餘油量為j的花費。

簡單的說,就是優先佇列優化的最短路演算法多了一維。

為了把所有可能的狀態考慮到,

每到一個點只有兩種操作:1、加一單位的油 2、更新能走到的下一個點。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 1005
#define M 10005
using namespace std;
int n,m,p[N],cnt,head[N],dp[N][110],que,ans;
int cap,st,ed;
bool vis[N][110];

struct Node{
    int id,oil,cost;
    bool operator <(const Node &b) const
    {
        return cost>b.cost;
    }
};

struct Edge{
    int to,nxt,val;
}edge[M*2];

void add(int x,int y,int z)
{
    cnt++;
    edge[cnt].nxt=head[x];
    edge[cnt].to=y;
    edge[cnt].val=z;
    head[x]=cnt;
}

bool bfs()
{
    memset(dp,0x3f,sizeof dp); memset(vis,0,sizeof vis);
    priority_queue<Node> q;
    Node now,cur,next;
    int id,cost,oil;
    now.id=st;
    now.cost=0;
    now.oil=0;
    q.push(now);
    while(!q.empty())
    {
        cur=q.top();
        q.pop();
        id=cur.id, cost=cur.cost, oil=cur.oil;
        if(id==ed)
        {
            ans=cost;
            return true;
        }
        if(vis[id][oil]) continue;
        vis[id][oil]=1;
        if(oil<cap)
        {
            next.id=id;
            next.oil=oil+1;
            next.cost=cost+p[id];
            if(!vis[id][next.oil] && dp[id][next.oil]>next.cost)
            {
                dp[id][next.oil]=next.cost;
                q.push(next);
            }
        }
        for(int i=head[id];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            int w=edge[i].val;
            if(oil>=w && dp[v][oil-w]>cost)
            {
                dp[v][oil-w]=cost;
                next.id=v;
                next.cost=cost;
                next.oil=oil-w;
                q.push(next);
            }
        }
    }
    return false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&p[i]);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z); add(y,x,z);
    }
    scanf("%d",&que);
    for(int i=1;i<=que;i++)
    {
        scanf("%d%d%d",&cap,&st,&ed);
        if(bfs())
        {
            printf("%d\n",ans);
        }
        else printf("impossible\n");
    }
    return 0;
}