题面描述
给定
个加油站,其中有一个是秋名山。
条无向边,每条边都有
,
为
从这条边走到
的距离,现在给你一辆车
,你需要驾驶这辆
从家到秋名山去飙车!但是,秋名山和家的位置都是不固定的,而且你的
的油箱也是不固定的,途中有些加油站,这些加油站的每个单位距离的油的价钱
不定,它们会变换,而且,你有时候不能到秋名山开车,因为路途有跤警
。先给定一个询问
,每个询问
,给出家
、秋名山
、以及
的油箱储量
,求最小费用.
输入格式
第一行给出
,
接下来一行,分别为
.
~
行,分别为
.
行,给出
接下来
行,给出每一个
初始化的油箱储量为
输出格式
对于每一个
若无解,输出“impossible”
否则,输出最小费用。
样例输入
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
样例输出
170
impossible
思路
既然这道题跑图,则
这里状态可以有两种选择,我们可以
- 停在这个加油站加油,
- 去别的加油站加油。
既然我们不知道在这个加油站加多少油,那就每一次只加一个单位的油,避免状态的损失,上限就是
.
仔细思考发现,这样很容易超时,且多出许多无用状态。
那尝试考虑优先队列
我们就可以很清晰地得到状态:
- 停在这里加一个单位的油
- 到别的加油站去
由于我们是保证最小花费w的(优先队列的性质),所以可以得到最小解。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
const int N=1e3+10;
const int M=1e4+10;
const int inf=0x3f3f3f3f;
struct edge{int x,y,next,d;}a[M<<1];int len,last[N];
void ins(int x,int y,int d){a[++len].x=x,a[len].y=y;a[len].d=d;a[len].next=last[x];last[x]=len;}
struct node
{
int w,f,x;//w为花费,f为油量,x为位置。
node(){}
node(int x,int f,int w):x(x),f(f),w(w){}
bool operator <(const node a)const{return w>a.w;}
//*this在<前面,a在<后面 ,交换时,*this.w若大于a.w,会把*this远离根,a靠近根,从而将大根堆变为小根堆。
};
int p[N],c[N][110];bool v[N][110];
int main()
{
int n,m,Q;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,d;scanf("%d%d%d",&x,&y,&d);ins(x,y,d);ins(y,x,d);}
scanf("%d",&Q);
while(Q--)
{
int st,ed,cw;scanf("%d%d%d",&cw,&st,&ed);
memset(v,false,sizeof(v));memset(c,0x3f,sizeof(c));
c[st][0]=0;
priority_queue<node>q;
q.push(node(st,0,0));
while(!q.empty())
{
node now=q.top();q.pop();
int x=now.x,f=now.f,w=now.w;
if(v[x][f])continue;
if(x==ed)break;
if(f<cw)
{
if(w+p[x]<c[x][f+1])
{
c[x][f+1]=w+p[x];
q.push(node(x,f+1,c[x][f+1]));
}
}
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y,d=a[k].d;
if(d<=f&&c[y][f-d]>w)
{
c[y][f-d]=w;
q.push(node(y,f-d,c[y][f-d]));
}
}
v[x][f]=true;
}
if(c[ed][0]==inf)puts("impossible");
else printf("%d\n",c[ed][0]);
}
return 0;
}