zoukankan      html  css  js  c++  java
  • 洛谷P5340 [TJOI2019]大中锋的游乐场

    原题链接 [TJOI2019]大中锋的游乐场

    题目描述

    大中锋正在一个游乐场里玩耍。游乐场里有很多娱乐设施,娱乐设施之间相互有道路相连,经过每一条路都需要花费一定的时间。

    为了方便游客,每一个娱乐设施旁都会配有一个小卖部,一部分小卖部会销售可乐,另一部分会销售汉堡。

    由于大中锋十分贪吃,所以每当他走到一个娱乐设施,他都会先去购买一杯可乐或一个汉堡,并把它们吃掉。

    但如果大中锋吃掉的汉堡数量比他喝掉的可乐数量多于k,那他就会感到很渴;如果喝掉的可乐数量比吃掉的汉堡数量多于k,那他就会感到很饿.

    现在大中锋正在第 a 个娱乐设施,他想前往第 b 个娱乐设施,但在他前进的路途中他不希望自己很渴或很饿。

    大中锋想知道自己在路上少花费多少时间。但由于大中锋很懒惰,他不想思考这个问题。你能帮助他解决这个问题吗?

    注意:大中锋非常贪吃,所以他到达每个点的第一件事是去吃(或者喝),才考虑其他的事情,所以在起始点和终点他都会去买汉堡(可乐),

    你也需要保证在这两个点他不会感到很饿或者很渴。

    输入输出格式

    输入格式:

    多样例输入,第一行输入一个正整数 TT 表示样例数。

    对于每一个样例:

    第一行三个数字 n,m,k , n 代表游乐场一共有多少个娱乐设施, m 代表游乐场一共有多少条道路, k 的意义如题面中所述。

    接下来有一行 n 个数字,第 i 个数字代表第 i 个小卖部销售的是什么, 1 代表可乐, 2 代表汉堡。

    接下来有 m 行输入,每行三个数字 p,q,t ,代表从第 p 个娱乐设施到第 q 个娱乐设施有一条双向道路,通过这条道路需要花费 t 单位时间。

    最后一行有两个整数 a,b,代表大中锋想从娱乐设施 a 前往娱乐设施 b 。

    输出格式:

    每组样例输出一行整数 t ,代表大中锋在路上既不会感到很渴也不会感到很饿的情况下,

    从娱乐设施 a 到娱乐设施 b花费的最少时间,如果无法达到,输出 1 。

    输入输出样例

    输入样例#1: 复制
    1
    2 1 1
    1 1
    1 2 1
    1 2
    输出样例#1: 复制
    -1
    输入样例#2: 复制
    1
    2 1 2
    1 1
    1 2 1
    1 2
    输出样例#2: 复制
    1

    说明

    数据范围

    对于 30% 的数据, 1000n50,m1000

    对于 100% 的数据, 10000n10000,m100000,k10,t10000

    对于所有数据,保证 T ≤ 10T10 ,且每个样例点的大数据不超过 22 个。

    题目补充说明

    • 路径不一定是简单路径
    • 大中锋可以多次经过一个节点,同时每次都会取得汉堡/可乐

    题解

    算法:Dijkstra单源最短路径

    题目要求路程上花费的最短时间,故很容易想到最短路算法。

    本题的特色在于求最短路时有一个限定条件——吃汉堡和可乐数量的差的绝对值不能超过k,

    而k的范围非常小(k10),所以可以按照每个状态吃汉堡和可乐数量的差将每1个点拆成2k个点,

    dis(i,j)表示从起点走到i号节点可乐数量-汉堡数量为j花费的最短时间;cola(i)表示i号点的可乐数量(卖可乐则为1,卖汉堡则为-1)

    则dis(i,j)=min{dis(k,j-cola(i))+路径长度},用dijkstra即可

    实现

    代码很简单,核心是dijkstra部分:

    1.初始化

    (1)定义node表示状态,用优先队列priority_queue存储

    struct node{
        int idx,tim,cola;
        node(int x,int y,int z){
            idx=x; tim=y; cola=z;
        }
        friend inline bool operator<(node x,node y){
            if(x.tim!=y.tim)
                return x.tim>y.tim;
            return x.cola>y.cola;
        }
    };

    (2)宽搜前插入起点,可乐数量为k(为了防止可乐数量为负数,加上基数k,控制可乐数量在0~2k之间)

    que.push(node(S,0,K+cola[S]));

    2.转移:

    根据dis(i,j)=min{dis(k,j-cola(i))+路径长度},套用dijkstra转移方程

    for(int i=head[idx];i;i=nxt[i]){
        int ii=col+cola[to[i]];
        if((ii>=0&&ii<=K*2)&&(!vis[to[i]][ii]&&tim+cst[i]<dis[to[i]][ii])){
            dis[to[i]][ii]=tim+cst[i];
            que.push(node(to[i],dis[to[i]][ii],ii));
        }
    }

    代码 

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int INF=0x3f3f3f3f,MAXN=1e4+50,MAXM=2e5+50,MAXK=21;
     5 int sz,head[MAXN],nxt[MAXM],to[MAXM],cst[MAXM];
     6 inline void add(int x,int y,int z){
     7     nxt[++sz]=head[x]; head[x]=sz; to[sz]=y; cst[sz]=z;
     8     nxt[++sz]=head[y]; head[y]=sz; to[sz]=x; cst[sz]=z;
     9 }
    10 int N,M,K,S,T,cola[MAXN];
    11 inline void Init(){
    12     scanf("%d%d%d",&N,&M,&K);
    13     for(int i=1;i<=N;i++){
    14         scanf("%d",cola+i);
    15         if(cola[i]==2)
    16             cola[i]=-1;
    17     }
    18     for(int i=1;i<=M;i++){
    19         int ii,jj,kk;
    20         scanf("%d%d%d",&ii,&jj,&kk);
    21         add(ii,jj,kk);
    22     }
    23     scanf("%d%d",&S,&T);
    24 }
    25 struct node{
    26     int idx,tim,cola;
    27     node(int x,int y,int z){
    28         idx=x; tim=y; cola=z;
    29     }
    30     friend inline bool operator<(node x,node y){
    31         if(x.tim!=y.tim)
    32             return x.tim>y.tim;
    33         return x.cola>y.cola;
    34     }
    35 };
    36 int dis[MAXN][MAXK],vis[MAXN][MAXK];
    37 inline void Dijkstra(){
    38     memset(dis,0x3f,sizeof(dis));
    39     memset(vis,0,sizeof(vis));
    40     priority_queue<node> que;
    41     que.push(node(S,0,K+cola[S]));
    42     while(que.size()){
    43         node cur=que.top();
    44         que.pop();
    45         int idx=cur.idx,tim=cur.tim,col=cur.cola;
    46         if(vis[idx][col]||tim>dis[idx][col])
    47             continue;
    48         vis[idx][col]=1;
    49         for(int i=head[idx];i;i=nxt[i]){
    50             int ii=col+cola[to[i]];
    51             if((ii>=0&&ii<=K*2)&&(!vis[to[i]][ii]&&tim+cst[i]<dis[to[i]][ii])){
    52                 dis[to[i]][ii]=tim+cst[i];
    53                 que.push(node(to[i],dis[to[i]][ii],ii));
    54             }
    55         }
    56     }
    57 }
    58 int ans=INF;
    59 inline void Output(){
    60     for(int i=0;i<=2*K;i++)
    61         if(dis[T][i]<ans)
    62             ans=dis[T][i];
    63     printf("%d
    ",ans==INF?-1:ans);
    64 }
    65 int Task;
    66 int main(){
    67     scanf("%d",&Task);
    68     while(Task--){
    69         Init();
    70         Dijkstra();
    71         Output();
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    Android 6.0权限
    从最简单的HelloWorld理解MVP模式
    DataSet、DataTable和DataGridView知识备忘
    Windows 窗体启动和关闭的事件顺序
    VB二进制文件读写
    C#操作符的重载
    虚方法(virtual)和抽象方法(abstract)的区别
    我的前端页面开发js简易有效环境
    css properties
    css属性值语法解读
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/10846224.html
Copyright © 2011-2022 走看看