题目描述
大中锋正在一个游乐场里玩耍。游乐场里有很多娱乐设施,娱乐设施之间相互有道路相连,经过每一条路都需要花费一定的时间。为了方便游客,每一个娱乐设施旁都会配有一个小卖部,一部分小卖部会销售可乐,另一部分会销售汉堡。
由于大中锋十分贪吃,所以每当他走到一个娱乐设施,他都会先去购买一杯可乐或一个汉堡,并把它们吃掉。但如果大中锋吃掉的汉堡数量比他喝掉的可乐数量多于 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;
}