装满的油箱

原题链接:装满的油箱

分析

算法

dijkstra+拆点图

时间复杂度

O(MlogNC)

思路

在刚写这题的时候,完全没有任何思路。因为通过分析题目,我们可以知道,其实是类似于求一个最短路。但是又跟典型的最短路不相同。因为需要算的其实是。

从起点走到终点的花费的最小值。但这个花费,让我有点迷茫了,花费需要考虑,在哪加多少油,才能使得车子,到达终点花费才能最少。

因为要素过多,所以迷茫了。但听完y总讲完,有了点思路和扩展。

我们来从头分析一下我们要求的要求,并标注一些重点。

从起点到终点的花费的最小值。花费需要考虑在哪多少油才能使车子到达终点花费最少。

我们来一点点的分析,最小值,依旧是告诉我们要用最短路来求。

在哪,则是另我们发现,对每一个点来说,它本身拥有的除了编号外,还有另外一个属性到该点的手的汽车油量,到相同点,但油量不同,则依旧是不同的状态点。这里我们发现可以用拆点图的方法将一个点拆分为,编号+油量的状态。

多少油,则是让我们发现了,我们在一个点的加油过程,可以看成是两个点的加边过程

\[(ver,c) => (ver,c+1) \]

通过+1,我们可以连接出一个编号的所有油量情况。

至此,我们就发现了,建立完拆点图后,题目就变为了求(S,0)=>sE,0)的最短路。

拓展

关于拆点图的一些想法吧,也不能叫拓展。

我们用到拆点图的情况,往往是一个点的情况有很复杂的状态。

但并不一定都很直接的摆在眼前。

例如这道题,我刚开始就被复杂的状态打晕了。但通过分析,我们可以知道,所有的转移,其实只要给点多加上一维状态即可。

但怎么发现,其实并不那么容易。

所以,在遇到一个图论问题时,拆分出所有的状态转移过程,是非常关键的。

拆分后,我们就可以明白一个点的状态有哪些,边的状态有哪些。

ACcode

#include<bits/stdc++.h>
using namespace std;
const int N = 1010,M = 2e4 + 10,C = 110;
int h[N],e[M],ne[M],w[M],idx;
int P[N];
int dist[N][C];
bool st[N][C];
int n,m;

struct Node
{
    int d,u,c;
    bool operator<(const Node &w) const
    {
        return d>w.d;
    }
};

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

int dijkstra(int c,int start,int end)
{
    priority_queue<Node> pq;
    memset(dist,0x3f,sizeof dist);
    memset(st, 0, sizeof st);
    dist[start][0]=0;
    pq.push({0,start,0});
    while(pq.size())
    {
        auto t = pq.top();
        pq.pop();
        
        if(t.u==end) return t.d;
        if(st[t.u][t.c]) continue;
        
        st[t.u][t.c]=1;
        if(t.c+1<=c)
        {
            if(dist[t.u][t.c+1]>t.d+P[t.u])
            {
                dist[t.u][t.c+1]=t.d+P[t.u];
                pq.push({dist[t.u][t.c+1],t.u,t.c+1});
            }
        }
        
        for(int i=h[t.u];~i;i=ne[i])
        {
            int j = e[i];
            if(t.c>=w[i])
            {
                if(dist[j][t.c-w[i]]>t.d)
                {
                    dist[j][t.c-w[i]]=t.d;
                    pq.push({dist[j][t.c-w[i]],j,t.c-w[i]});
                }
            }
        }
    }
    
    return -1;
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(h, -1, sizeof h);
    for(int i=0;i<n;i++) scanf("%d",&P[i]);
    
    while (m -- )
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    
    int q;
    scanf("%d",&q);
    while(q--)
    {
        int c,s,e;
        scanf("%d%d%d",&c,&s,&e);
        int t = dijkstra(c,s,e);
        if(t==-1) puts("impossible");
        else printf("%d\n",t);
    }
    
    return 0;
}
posted @ 2021-09-09 20:29  艾特玖  阅读(70)  评论(0)    收藏  举报