已知一个连通无向图,其中一些点有加油站(每个加油站油价不同),现在S点有一个油箱大小为t前往T的车。求最小油费花销。
经典题.考虑从A加油站前往B加油站,要么在A加满,要么在B恰好用完。因此可以拆点最短路。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "w", stdout)
#define scan(x) scanf("%d", &x)
#define mp make_pair
#define pb push_back
#define sqr(x) (x) * (x)
#define pr(x) printf("Case %d: ",x)
#define prn(x) printf("Case %d:\n",x)
#define prr(x) printf("Case #%d: ",x)
#define prrn(x) printf("Case #%d:\n",x)
#define lowbit(x) (x&(-x))
#define fi first
#define se second
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
const int maxn=1005;
int dis[maxn][maxn];
struct edge
{
int to,cost;
bool operator < (const struct edge &p)const
{return cost>p.cost;}
};
vector<edge> g[maxn];
priority_queue<edge> q;
bitset<maxn> vis;
int n,m,k,T,lim;
pii sta[125];
void Dijkstra(int st)
{
vis.reset();
for(int i=1;i<=n;i++)dis[st][i]=1e9;
dis[st][st]=0;
while(!q.empty())q.pop();
q.push({st,0});
while(!q.empty())
{
edge t=q.top();q.pop();
int id=t.to;
vis.set(t.to);
for(edge p : g[id])
if(dis[st][p.to]>dis[st][id]+p.cost)
{
dis[st][p.to]=dis[st][id]+p.cost;
q.push({p.to,dis[st][p.to]});
}
while(!q.empty() && vis.test(q.top().to))q.pop();
}
}
typedef long long ll;
typedef pair<ll,pii > plii;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define INF (1000000000000000LL)
#define MEM(a) memset(a,0,sizeof(a));
int cnt;
pii p[300*122*2];
int find(int x,int y) {
return lower_bound(p+1,p+1+cnt,mp(x,y))-p-1;
}
struct Edge{
int from,to;
ll dist;
};
struct HeapNode {
ll d;
int u;
bool operator< (const HeapNode& rhs) const {
return d > rhs.d;
}
};
struct Dijkstr {
int n,m;
#define MAXN (300*122*2)
vector<Edge> edges;
vector<int> G[MAXN];
bool done[MAXN];
ll d[MAXN];
int p[MAXN]; //最短路中上一条边
int pnode[MAXN];
void addedge(int u,int v,ll w){
edges.pb((Edge){u,v,w});
G[u].pb(m++);
}
void init(int _n){
n=_n; m = 0;
Rep(i,n) G[i].clear();
edges.clear();
}
void dijkstra(int s) {
priority_queue<HeapNode> Q;
Rep(i,n) d[i]=INF,pnode[i]=-1;
d[s]=0;
MEM(done)
Q.push((HeapNode){0,s});
while(!Q.empty()) {
HeapNode x=Q.top(); Q.pop();
int u=x.u;
if (done[u]) continue;
done[u]=1;
int mm=G[u].size();
Rep(i,mm) {
Edge e = edges[G[u][i]];
if (d[e.to]>d[u]+e.dist) {
d[e.to]=d[u]+e.dist;
p[e.to]=G[u][i];
pnode[e.to]=u;
Q.push((HeapNode){d[e.to],e.to});
}
}
}
}
}S1;
int main()
{
// freopen("H.data","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&n,&m,&k,&lim);
for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g[x].pb({y,z});g[y].pb({x,z});
}
for(int i=1;i<=k;i++)
{
scanf("%d%d",&sta[i].fi,&sta[i].se);
Dijkstra(sta[i].fi);
}
int st,ed;
scanf("%d%d",&st,&ed);
int x=0;For(i,k) if (st==sta[i].fi) x=i;
int y=0;For(i,k) if (st==sta[i].fi) y=i;
++k;
sta[k].fi=ed,sta[k].se=0;
Dijkstra(st);
Dijkstra(ed);
cnt=0;
For(i,k) {
p[++cnt]=mp(i,0);
if (i==k) continue;
p[++cnt]=mp(i,lim);
For(j,k) {
if (i!=j) {
p[++cnt]=mp(i,lim-dis[sta[j].fi][sta[i].fi]);
p[++cnt]=mp(i,dis[sta[j].fi][sta[i].fi]);
}
}
}
For(i,k) For(j,k) {
if (dis[sta[j].fi][sta[i].fi]!=dis[sta[i].fi][sta[j].fi]) puts("s");
}
sort(p+1,p+1+cnt);
cnt=unique(p+1,p+1+cnt)-p-1;
S1.init(cnt);
Fork(i,2,cnt) {
if (p[i].fi==p[i-1].fi ) {
S1.addedge(find(p[i-1].fi,p[i-1].se),
find(p[i].fi,p[i].se),
(p[i].se-p[i-1].se)*sta[p[i].fi].se );
}
}
For(i,k-1) {
For(j,k) if (i!=j){
if (dis[sta[i].fi][sta[j].fi]<=lim) {
S1.addedge(find(i,dis[sta[i].fi][sta[j].fi] ) , find(j,0), 0);
if(j^k)
S1.addedge(find(i,lim),find(j,lim-dis[sta[i].fi][sta[j].fi] ),0);
}
}
}
S1.dijkstra(find(x,0));
cout<<S1.d[find(k,0)]<<endl;
}
return 0;
}