[TJOI2019]大中锋的游乐场

题目描述

大中锋正在一个游乐场里玩耍。游乐场里有很多娱乐设施,娱乐设施之间相互有道路相连,经过每一条路都需要花费一定的时间。为了方便游客,每一个娱乐设施旁都会配有一个小卖部,一部分小卖部会销售可乐,另一部分会销售汉堡。

由于大中锋十分贪吃,所以每当他走到一个娱乐设施,他都会先去购买一杯可乐或一个汉堡,并把它们吃掉。但如果大中锋吃掉的汉堡数量比他喝掉的可乐数量多于 kk ,那他就会感到很渴;如果喝掉的可乐数量比吃掉的汉堡数量多于 kk ,那他就会感到很饿。

现在大中锋正在第 aa 个娱乐设施,他想前往第 bb 个娱乐设施,但在他前进的路途中他不希望自己很渴或很饿。大中锋想知道自己在路上少花费多少时间。但由于大中锋很懒惰,他不想思考这个问题。你能帮助他解决这个问题吗?

注意:大中锋非常贪吃,所以他到达每个点的第一件事是去吃(或者喝),才考虑其他的事情,所以在起始点和终点他都会去买汉堡(可乐),你也需要保证在这两个点他不会感到很饿或者很渴。

输入格式

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

对于每一个样例:

第一行三个数字 n,m,kn,m,k , nn 代表游乐场一共有多少个娱乐设施, mm 代表游乐场一共有多少条道路, kk 的意义如题面中所述。接下来有一行 nn 个数字,第 ii 个数字代表第 ii 个小卖部销售的是什么, 11 代表可乐, 22 代表汉堡。接下来有 mm 行输入,每行三个数字 p,q,tp,q,t ,代表从第 pp 个娱乐设施到第 qq 个娱乐设施有一条双向道路,通过这条道路需要花费 tt 单位时间。最后一行有两个整数 a,ba,b ,代表大中锋想从娱乐设施 aa 前往娱乐设施 bb 。

输出格式

每组样例输出一行整数 tt ,代表大中锋在路上既不会感到很渴也不会感到很饿的情况下,从娱乐设施 aa 到娱乐设施 bb花费的最少时间,如果无法达到,输出 -1−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%30% 的数据, n\leq 50,m\leq 1000n≤50,m≤1000

对于 100%100% 的数据, n\leq 10000,m\leq 100000,k\leq 10,t\leq 10000n≤10000,m≤100000,k≤10,t≤10000

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

题目补充说明

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

思路

如果没有可乐汉堡的限制,就是一道很简单的最短路,所以我们也考虑在最短路上做文章。对于每个点,有效状态是有限的。用Ca表示喝了可乐的数量,用Cb表示吃了汉堡的数量,有效的状态点其实是节点数量(2k + 1)×(2k+1) 个。所以我们在进行最短路的时候保存dist[i][j]的值。i表示到达第i个 节点,j表示(Ca - Cb) == j,然后进行最短路即可。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 10050,K = 11,V = N * 21,E = 100050 * 21 * 2;
int To[E],Dis[E],Ne[E],He[V],_k;
void add(int x,int y,int z){
	++_k; To[_k] = y,Dis[_k] = z,Ne[_k] = He[x],He[x] = _k;
}
int T;
int cnt;
int qa,qb,start;
int n,m,k,tp[N],p1[N],p2[N][K],p3[N][K];
int Getp(int x,int t){
	if (abs(t) > k) return 0;
	if (!t) return p1[x];
	return t > 0 ? p2[x][t] : p3[x][-t];
}
ll dis[V],ans,INF = 1ll<<61;
struct Node{
	int x; ll d;
	bool operator < (Node w) const{ return d > w.d; }
}tmp;
priority_queue<Node>Heap;
void Dij(){
	int i,p,x,y;
	while (!Heap.empty()) Heap.pop();
	for (i = 1; i <= cnt; ++i) dis[i] = INF;
	dis[start] = 0;
	tmp.x = start,tmp.d = 0,Heap.push(tmp);
	while (!Heap.empty()){
		tmp = Heap.top(); Heap.pop();
		if (tmp.d > dis[tmp.x]) continue;
		x = tmp.x;
		for (p = He[x]; p ; p = Ne[p]){
			y = To[p];
			if (dis[y] > dis[x] + Dis[p]){
				dis[y] = dis[x] + Dis[p];
				tmp.x = y,tmp.d = dis[y];
				Heap.push(tmp);
			}
		}
	}
}
int main(){
	int i,j,x,y,z,lx,ly;
	cin>>T;
	while (T--)
	{
		_k = cnt = 0;
		cin>>n>>m>>k;
		for (i = 1; i <= n; ++i) 
		{
			cin>>tp[i];
			if(tp[i]!=1) tp[i]=-1; 
		}
		for (i = 1; i <= n; ++i)
		{
			p1[i] = ++cnt;
			for (j = 1; j <= k; ++j){p2[i][j] = ++cnt; p3[i][j] = ++cnt;}
		}
		memset(He,0,sizeof(int) * (cnt+5));
		while (m--)
		{
			cin>>x>>y>>z;
			for (i = -k; i <= k; ++i)
			{
				lx = Getp(x,i);
				ly = Getp(y,i + tp[y]);
				if (ly) add(lx,ly,z);
			}
			swap(x,y);
			for (i = -k; i <= k; ++i)
			{
				lx = Getp(x,i);
				ly = Getp(y,i + tp[y]);
				if (ly) add(lx,ly,z);
			}
		}
		cin>>qa>>qb;
		start = Getp(qa,tp[qa]);
		Dij();
		ans = INF;
		for (i = -k; i <= k; ++i){
			x = Getp(qb,i);
			if (dis[x] < ans) ans = dis[x];
		}
		if (ans == INF) puts("-1"); else cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值