题目描述
N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。
1.从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。
2.从黑洞跃迁到白洞,消耗的燃料值增加delta。
3.路径两端均为黑洞或白洞,消耗的燃料值不变化。
作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i]的燃料。现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。
输入输出格式
输入格式:
第1行:2个正整数N,M
第2行:N个整数,第i个为0表示虫洞i开始时为白洞,1表示黑洞。
第3行:N个整数,第i个数表示虫洞i的质量w[i]。
第4行:N个整数,第i个数表示在虫洞i停留消耗的燃料s[i]。
第5..M+4行:每行3个整数,u,v,k,表示在没有影响的情况下,从虫洞u到虫洞v需要消耗燃料k。
输出格式:
一个整数,表示最少的燃料消耗。
输入输出样例
输入样例
4 5
1 0 1 0
10 10 100 10
5 20 15 10
1 2 30
2 3 40
1 3 20
1 4 200
3 4 200
输出样例
130
说明
对于30%的数据: 1<=N<=100,1<=M<=500
对于60%的数据: 1<=N<=1000,1<=M<=5000
对于100%的数据: 1<=N<=5000,1<=M<=30000
其中20%的数据为1<=N<=3000的链
1<=u,v<=N, 1<=k,w[i],s[i]<=200
拆点。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
int n, m, thea[5005], tcnt, hea[10005], cnt, sx[5005], w[5005], s[5005];
int uu, vv, ww, dis[10005];
bool inq[10005];
queue<int> d;
struct Te{
int too, nxt, val;
}te[30005];
struct Edge{
int too, nxt, val;
}edge[120005];
void add_tedge(int fro, int too, int val){
te[++tcnt].nxt = thea[fro];
te[tcnt].too = too;
te[tcnt].val = val;
thea[fro] = tcnt;
}
void add_edge(int fro, int too, int val){
edge[++cnt].nxt = hea[fro];
edge[cnt].too = too;
edge[cnt].val = val;
hea[fro] = cnt;
}
void bui(int u){
add_edge(u, u+n, s[u]);
add_edge(u+n, u, 0);
for(int i=thea[u]; i; i=te[i].nxt){
int t=te[i].too;
int delta=abs(w[t]-w[u]);
if(sx[u]!=sx[t]){
add_edge(u, t, te[i].val+delta);
add_edge(u+n, t+n, max(0, te[i].val-delta));
}
else{
add_edge(u, t+n, te[i].val);
add_edge(u+n, t, te[i].val);
}
}
}
void spfa(){
memset(dis, 0x3f, sizeof(dis));
if(sx[1]){
dis[1] = 0;
d.push(1);
inq[1] = true;
}
else{
dis[1+n] = 0;
d.push(1+n);
inq[1+n] = true;
}
while(!d.empty()){
int x=d.front();
d.pop();
inq[x] = false;
for(int i=hea[x]; i; i=edge[i].nxt){
int t=edge[i].too;
if(dis[t]>dis[x]+edge[i].val){
dis[t] = dis[x] + edge[i].val;
if(!inq[t]){
inq[t] = true;
d.push(t);
}
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1; i<=n; i++)
scanf("%d", &sx[i]);
for(int i=1; i<=n; i++)
scanf("%d", &w[i]);
for(int i=1; i<=n; i++)
scanf("%d", &s[i]);
for(int i=1; i<=m; i++){
scanf("%d %d %d", &uu, &vv, &ww);
add_tedge(uu, vv, ww);
}
for(int i=1; i<=n; i++)
bui(i);
spfa();
printf("%d", min(dis[n], dis[n+n]));
return 0;
}