题目描述
鸡尾酒被困入了一个迷宫!
这个迷宫总共有n个房间组成,鸡尾酒初始在1号房间,n号房间为迷宫的出口。每进入一次第i个房间都需要缴纳ai的过路费(包括初始的一号房间)。每个房间有一张纸条和一个箱子。纸条上写着的数字di代表鸡尾酒下一个可以到达的房间编号。
鸡尾酒也可以选择花费bi的金钱打开箱子,箱子中有一个密码ci,打开箱子之后鸡尾酒可以移动到i+k号房间,其中c可被k整除。但如果i+k>n,则不能移动。
求鸡尾酒从走出迷宫的最小花费。若鸡尾酒无法走出迷宫,输出-1。
输入描述
输入第一行一个n,代表迷宫共有n个房间(n<2e5)
接下来有n行,每行包含四个整数ai,bi,ci,di,意义如题面所描述。其中(ai,bi,ci,di≤2e5)
输出描述
输出一行一个整数代表走出迷宫的最小花费。
样例输入 1
5 1 2 2 4 2 2 2 2 1 1 2 2 100 1 1 1 1 1 1 1样例输出 1
6最短路板子,图已经在数据中建好,只需要在dij中处理开宝箱得花费和进入房间得费用最小即可
//没有建图得操作是因为数据中已经给建好了房间得联通关系
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 210000;
const ll inf = 1e15;
int a[maxn],b[maxn],c[maxn],d[maxn];
bool vis[maxn];
ll dis[maxn];//存储到第i个房间得花费
int n,m;
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
void dij(int s)
{
for (int i=1;i<=n;++i)
{
dis[i]=inf;
vis[i]=0;
}
dis[s]=a[1];
for (int i=1;i<=n;++i)
q.push(make_pair(dis[i],i));
while (!q.empty())
{
int u=q.top().second;
q.pop();
if (vis[u]) continue ;
vis[u]=1;
if (dis[d[u]]>dis[u]+a[d[u]]) {//将直接进入房间的花费更新到dis数组里
dis[d[u]]=dis[u]+a[d[u]];
q.push(make_pair(dis[d[u]],d[u]));
}
for (int i=1;i*i<=c[u];i++)//因为有c能被k整除的条件,并且2e5的数据也不大,直接遍历找到c的因子,判断是否会超过最后一个房间,并将花费更新进dis数组
{
if (c[u]%i==0)
{
int dd=i;
if (dd+u<=n)
{
if (dis[dd+u]>dis[u]+a[dd+u]+b[u])
{
dis[dd+u]=dis[u]+a[dd+u]+b[u];
q.push(make_pair(dis[dd+u],dd+u));
}
}
dd=c[u]/i;
if (dd+u<=n)
{
if (dis[dd+u]>dis[u]+a[dd+u]+b[u])
{
dis[dd+u]=dis[u]+a[dd+u]+b[u];
q.push(make_pair(dis[dd+u],dd+u));
}
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i]>>c[i]>>d[i];
}
dij(1);
if(dis[n]==inf) cout<<-1<<endl;
else cout<<dis[n]<<endl;
return 0;
}
也可以用spfa,也是板子操作。。留坑