西北大学2019年春季校赛 G题 房间迷宫

题目链接:传送门(密码:jwjtxdy)
题意: 鸡尾酒被困入了一个迷宫!这个迷宫总共有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) 输出描述 输出一行一个整数代表走出迷宫的最小花费。
思路: 明显的最短路问题,但是题目多了一类路径,即通过开密码箱后能走的路径,这只需我们全部枚举出来即可,具体操作请看代码.

//因为在下很懒又怕爆int我都开了long long ,很多地方其实没必要。
#include 
#include 
#include 
#define inf 1e15
using namespace std;

typedef pair<long , long > P;
const int maxn = 2e5+7;
struct  edge{
    long long to,cost;
};
vector<edge> v[maxn];
vector<long long> yinzi[maxn];
long long n;
long long a[maxn],b[maxn],c[maxn],d[maxn];
long long dis[maxn],vis[maxn];

long long disjike() {//最基本的dijkstra算法+优先队列优化
    priority_queue< P,vector<P>,greater<P> > q;
    for(int i=1;i<=n;++i) {
        vis[i]=0;
        dis[i]=inf;
    }
    dis[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty()) {
        P s = q.top();q.pop();
        long long node =s.second;
        if(vis[node]==1) continue;
        vis[node] = 1;
        for(int i = 0;i<v[node].size();i++) {
            struct edge ss = v[node][i];
            if(dis[ss.to]>dis[node]+ss.cost) {
                dis[ss.to] = dis[node] + ss.cost;
                q.push(make_pair(dis[ss.to],ss.to));
            }
        }
    }
    return dis[n]+a[1];
}

int main() {
    for(int i=1;i<maxn;++i) {
        for(int j = i;j<maxn;j+=i) {
            yinzi[j].push_back(i);//先把每个数的因子有哪些打个表,由调和级数可知复杂度为o(nlog n)
        }
    }
    cin>>n;
    for(int i=1;i<=n;++i) {
        cin>>a[i]>>b[i]>>c[i]>>d[i];
    }
    struct edge m;
    for(int i=1;i<=n;i++) {
        if(d[i]!=i) {//把原本就能走的路径储存
            m.to = d[i];
            m.cost = a[d[i]];
            v[i].push_back(m);
        }
        for(int j = 0;j<yinzi[c[i]].size();++j){//把开密码箱的路求出来并储存
            long long k = yinzi[c[i]][j];
            if(k+i>n) break;
            m.to = i+k;
            m.cost = a[i+k]+b[i];
            v[i].push_back(m);
        }
    }
    cout<<disjike()<<endl;
    return 0;
}

你可能感兴趣的:(西北大学2019年春季校赛 G题 房间迷宫)