POJ - 3635 Full Tank? 最短路(dj)+记忆化搜索

题目链接

题意:有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);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值