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;
}