P8385 题解

· · 题解

题目大意

我觉得这道题最大的难点就是题目的意思,在此我简单说明一下。一开始,商人就有 1kg 黄金(也就是说没有费用)。接着就是转化,这是在过边境前后都可以进行的。还有就是在过边境之后经过若干次转化后,商人手上拿着的必须是黄金。

是不是感觉换了道题???

思路

我用的是 Dijkstra,这很好想。为了解决过边境的问题,对于每种金属都建两个点,分别是过边境前的和过边境后的。对于转化,直接连两种所给的金属。对于交税,直接把两个同金属过边境前和过边境后的点连边,费用为该金属的单价的一半。最后套模板就可以了。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s=1,h[500100],dis[500100],l,vis[500100],x,y,z,t;
struct node
{
    int dis,pos;
    bool operator <(const node &x)const
    {
        return x.dis<dis;
    }
};
inline int read()
{
    int k=0,f=0;char c=getchar();
    for(;!isdigit(c);c=getchar()) f|=c=='-';
    for(;isdigit(c);c=getchar()) k=(k<<1)+(k<<3)+(c^48);
    return f?-k:k;
}
priority_queue<node> q;
struct edge
{
    int v,next,w;
}e[500100];
inline void add(int x,int y,int z)
{
    e[++l].v=y;
    e[l].w=z;
    e[l].next=h[x];
    h[x]=l;
}
inline void d()//模板 
{
    for(int i=1;i<=t;i++) dis[i]=inf;
    dis[s]=0;
    q.push((node){0,s});
    while(!q.empty())
    {
        node t=q.top();
        q.pop();
        int k=t.pos;
        if(vis[k]) continue;
        vis[k]=1;
        for(int i=h[k];i;i=e[i].next)
        {
            if(dis[e[i].v]>dis[k]+e[i].w)
            {
                dis[e[i].v]=dis[k]+e[i].w;
                if(!vis[e[i].v]) q.push((node){dis[e[i].v],e[i].v});
            }
        }
    }
}
int main()
{
    n=read();
    t=2*n;
    for(int i=1;i<=n;i++) add(i,i+n,read()*0.5);//依法纳税  
    m=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z);//过边境前的转化 
        add(x+n,y+n,z);//过边境后的转化 
    }
    d();
    printf("%d",dis[n+1]);
    return 0;
}