洛谷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\n",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
posted @ 2019-05-10 19:11  guoshaoyang  阅读(247)  评论(0编辑  收藏  举报