假期計劃
jzoj 3936
題目大意
給你一個有向圖(),現在有一些作爲樞紐的點,且保證每一條邊的兩個點至少有一個是樞紐點,現在給q個詢問,問某一個點到另一個點的最短路,你只需輸出可以到達的數量,和可以到達的最短路之和
輸入樣例
3 3 1 2
1 2 10
2 3 10
2 1 5
2
1 3
3 1
輸出樣例
1
20
數據範圍
對於 30%的數據,
對於 100%的數據,
樣例說明
對於第一個航班,唯一可行的路線是,花費 20。
解題思路
因爲樞紐點很少,我們對於每一個樞紐點跑一邊
如果詢問的出發點是樞紐點,那就是直接最短路的值
如果不是,那和他相連的就都是,然後計算這條邊加和他相連的點到終點的最短路就是結果
代碼
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll n, m, k, q, x, y, z, tot, num, sum, ans, p[20010], v[20010], head[20010], b[210][20010];
struct rec
{
ll to, l, next;
}a[20010];
void spfa(ll x)
{
memset(b[v[x]], 127/3, sizeof(b[v[x]]));
b[v[x]][x] = 0;//以第x個樞紐爲起點到各個點的最短路
p[x] = 1;
queue<ll>d;
d.push(x);
while(!d.empty())
{
ll h = d.front();
d.pop();
for (ll i = head[h]; i; i = a[i].next)
if (b[v[x]][h] + a[i].l < b[v[x]][a[i].to])
{
b[v[x]][a[i].to] = b[v[x]][h] + a[i].l;
if (!p[a[i].to])
{
p[a[i].to] = 1;
d.push(a[i].to);
}
}
p[h] = 0;
}
}
int main()
{
scanf("%lld%lld%lld%lld", &n, &m, &k, &q);
for (ll i = 1; i <= m; ++i)
{
scanf("%lld%lld%lld", &x, &y, &z);
a[++tot].to = y;
a[tot].l = z;
a[tot].next = head[x];
head[x] = tot;
}
for (ll i = 1; i <= k; ++i)
{
scanf("%lld", &x);
v[x] = i;//記錄下他是第幾個,方便減小內存
spfa(x);
}
for (ll i = 1; i <= q; ++i)
{
scanf("%lld%lld", &x, &y);
sum = 200000010;
if (v[x]) sum = min(sum, b[v[x]][y]);//他就是樞紐
for (ll j = head[x]; j; j = a[j].next)
if (v[a[j].to])
sum = min(sum, a[j].l + b[v[a[j].to]][y]);//相連的樞紐
if (sum <= 200000000)
{
num++;
ans += sum;
}
}
printf("%lld\n%lld", num ,ans);
return 0;
}