题意:有n个城市m条道路,开车经过道路需要消耗道路长度相等的油,每个城市的油价不同,有q个询问,每次询问油箱容量为c的时候,油箱初始为空,从s城走到e城所需的最小费用。
思路:记忆化搜索,状态为第i个城市,目前油的数量为j。在dj的基础上进行记忆化搜索,不用每次搜索直接枚举到油箱加满的状态,可以通过搜索自己扩展。要扩展的状态若已经到终点了,说明之后扩展的状态cost必定比该cost大,所以这个状态的cost就是答案了。
#include<cstdio>
#include<vector>
#include<queue>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define NUM 1100
#define INF 0x3f3f3f3f
#define WEIGHT 110
int n,m;
int p[NUM];
struct edge
{
int w,to;
};
struct DP
{
int vertex,fuel,cost;
bool operator>(const DP& x)const
{
return cost>x.cost;
}
};
priority_queue < DP , vector<DP> , greater <DP> > q;
vector < edge > l[NUM];
int dp[NUM][WEIGHT];
bool vis[NUM][WEIGHT];//记录已经扩展过的状态
void solve(int st,int en,int limit)
{
memset(dp,INF,sizeof(dp));
memset(vis,false,sizeof(vis));
while(!q.empty())q.pop();
DP x,y;
int i;
x.vertex=st;
x.fuel=0;
x.cost=0;
dp[st][0]=0;
q.push(x);
while(!q.empty())
{
x=q.top();
q.pop();
vis[x.vertex][x.fuel]=true;
if(x.vertex==en)//当前要扩展的状态若已经到终点了,说明之后的路径必然没有此结果小,所以此结果即为答案
{
printf("%d\n",x.cost);
return ;
}
y.fuel=x.fuel+1;
if(x.fuel<limit&&dp[x.vertex][y.fuel]>dp[x.vertex][x.fuel]+p[x.vertex]&&!vis[x.vertex][y.fuel])//只需要扩展+1,之后+1的状态出队后即可扩展出+2...以此类推即可扩展到油箱加满
{
y.cost=dp[x.vertex][y.fuel]=dp[x.vertex][x.fuel]+p[x.vertex];
y.vertex=x.vertex;
q.push(y);
}
for(i=0;i<l[x.vertex].size();++i)
{
y.vertex=l[x.vertex][i].to;
y.fuel=x.fuel-l[x.vertex][i].w;
if(y.fuel<0||vis[y.vertex][y.fuel])continue ;
if(dp[y.vertex][y.fuel]>dp[x.vertex][x.fuel])
{
y.cost=dp[y.vertex][y.fuel]=dp[x.vertex][x.fuel];
q.push(y);
}
}
}
printf("impossible\n");
}
int main()
{
scanf("%d%d",&n,&m);
edge x;
int t1,t2;
int q,c;
for(int i=0;i<n;++i)
scanf("%d",&p[i]);
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&t1,&t2,&x.w);
x.to=t2;
l[t1].push_back(x);
x.to=t1;
l[t2].push_back(x);
}
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d",&c,&t1,&t2);
solve(t1,t2,c);
}
}