Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7461 | Accepted: 2409 |
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
题目翻译:
给出N个城市,M条路,然后给出N个城市的油价,然后给出始发城市S,目的城市E,和所使用交通工具的油箱容量。求从S到E的最小花费。
这个题目可以开一个二维数组 dp[i][j] 代表从S到到城市 i 所剩油量为J时候的最小花费。
当走到一个城市的时候:
在油箱未满的情况可以选择加一升的油。
或者是在油充足的情况下直接去其他城市。
为什么每次只考虑加一升。因为对于每一点,我们都要考虑所有能到的状态。就是抵达一个城市的时候,它的油量可以是0~Capacity。所以
我们到达一个点后一升一升的加油,加到某升的时候,可以走到一些其他地方,在加一升后,可能就又可以走到其他之前不能到的相邻点。
一个城市,不同的油量,是会影响到其他的城市的状态的。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#define inf 0x3f3f3f3f
using namespace std;
/**dp[i][j]代表走到城市i还剩j油量的时候的最小花费,走到城市i后,
可以考虑加一升油(为啥要加一升,主要是考虑一升一升的去加直到加
满,因为每加一升油也许就可以走到其他相邻的地方了,所以要看每加一
升油,求对其他城市所造成的影响)。或是在油够走到其他地方的情况下
不加油直接走过去*/
const int maxn = 1002;
const int maxm = 10003;
int N,M;
int price[maxn]; ///每个城市的油价
int dp[maxn][102]; ///代表走到城市i,还剩j油量的时候的最小花费。
int vis[maxn][102]; ///用来标记某种状态是否到过的数组
int S,D,V; ///起点,终点,油箱容量。
int head[maxn];
struct Edge
{
int v;
int weight;
int next;
}edge[maxm<<2];
struct node
{
int u;
int cost; ///走到该点的花费
int oil; ///走到该点的剩余油量。
bool operator<(const node &a) const ///花费小的先出队
{
return a.cost<cost;
}
};
int BFS()
{
node now,nex;
int i;
memset(vis,0,sizeof(vis));
memset(dp,inf,sizeof(dp));
priority_queue<node>qu; ///花费作为优先权
now.u = S; ///起点
now.oil = 0; ///起始油量
now.cost = 0; ///起始花费
dp[S][0] = 0;
qu.push(now);
while(!qu.empty())
{
now = qu.top();
qu.pop();
int u = now.u;
int cost = now.cost;
int oil = now.oil;
vis[u][oil] = 1;
///考虑在这个地方加一升的油。
if(now.u == D)
{
return now.cost;
}
///走到了终点,返回的值就是最小值
///在当前基础上加一升油不超过油箱容量,且下一个状态没有到过,
if(oil+1<=V && vis[u][oil+1]==0 && dp[u][oil]+price[u]<dp[u][oil+1])
{
dp[u][oil+1] = dp[u][oil]+price[u];
nex.u = u;
nex.oil = oil+1;
nex.cost = dp[u][oil+1];
qu.push(nex);
}
///如果剩余油量能直接开车到与u相邻的城市,就直接开车过去
for(i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
int w = edge[i].weight;
if(oil>=w && vis[v][oil-w]==0 && cost<dp[v][oil-w])
{
dp[v][oil-w] = cost;
nex.u = v;
nex.oil = oil-w;
nex.cost = cost;
qu.push(nex);
}
}
}
return -1;
}
int main()
{
int u,v,d,q;
while(~scanf("%d%d",&N,&M)) ///N个城市,M条边
{
memset(head,-1,sizeof(head)); ///head[u]存放,以u为始点的边的首地址
for(int i = 0; i < N; i++) ///输入N个城市的汽油价格
scanf("%d",&price[i]);
int j = 0;
for(int i = 0; i < M; i++) ///存储边,是无向图
{
scanf("%d%d%d",&u,&v,&d);
edge[j].v = v;
edge[j].weight = d;
edge[j].next = head[u];
head[u] = j;
j++;
edge[j].v = u;
edge[j].weight = d;
edge[j].next = head[v];
head[v] = j;
j++;
}
scanf("%d",&q);
while(q--) ///Q次询问
{
scanf("%d%d%d",&V,&S,&D);
int ans = BFS();
if(ans == -1)
printf("impossible\n");
else
printf("%d\n",ans);
}
}
return 0;
}