首页 > 代码库 > 虫洞 (C++)
虫洞 (C++)
虫洞 |
难度级别:C; 运行时间限制:1000ms; 运行空间限制:256000KB; 代码长度限制:2000000B |
试题描述
|
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 【样例说明】 按照1->3->4的路线。
|
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
return x*f;
}
const int maxn=10010;
const int maxm=1000010;
const int INF=1000000000;
struct Dijkstra {
int n,m,first[maxn],next[maxm];
struct Edge {int to,dist;}edges[maxm];
int done[maxn],d[maxn];
struct HeapNode {
int u,d;
bool operator < (const HeapNode& ths) const {return d>ths.d;}
};
void init(int n) {
this->n=n;m=0;
memset(first,0,sizeof(first));
}
void AddEdge(int u,int v,int w) {
//printf("%d --> %d %d\n",u,v,w);
edges[++m]=(Edge){v,w};next[m]=first[u];first[u]=m;
}
void solve(int s) {
rep(i,1,n) d[i]=INF,done[i]=0;
priority_queue<HeapNode> Q;
Q.push((HeapNode){s,0});d[s]=0;
while(!Q.empty()) {
int x=Q.top().u;Q.pop();
if(done[x]) continue;done[x]=1;
ren {
Edge& e=edges[i];
if(d[e.to]>d[x]+e.dist) {
d[e.to]=d[x]+e.dist;
Q.push((HeapNode){e.to,d[e.to]});
}
}
}
}
}sol;
//1---n 0 n+1----2*n 1
int n,m,type[maxn],w[maxn],s[maxn],u[maxn*3],v[maxn*3],k[maxn*3];
int first[maxn],next[maxn*3];
void Add(int x,int v) {
next[v]=first[x];first[x]=v;
}
int main() {
n=read();m=read();
rep(i,1,n) type[i]=read();
rep(i,1,n) w[i]=read();
rep(i,1,n) s[i]=read();
rep(i,1,m) u[i]=read(),v[i]=read(),k[i]=read(),Add(u[i],i);
sol.init(n*2);
rep(x,1,n*2) {
if(x<=n) sol.AddEdge(x,x+n,type[x]*s[x]);
else sol.AddEdge(x,x-n,(type[x-n]^1)*s[x-n]);
if(x<=n) ren {
if(type[x]==type[v[i]]) sol.AddEdge(x,v[i]+n,k[i]);
else if(type[x]) sol.AddEdge(x,v[i]+n,k[i]+abs(w[x]-w[v[i]]));
else sol.AddEdge(x,v[i]+n,max(0,k[i]-abs(w[x]-w[v[i]])));
}
else for(int i=first[x-n];i;i=next[i]) {
if(type[x-n]==type[v[i]]) sol.AddEdge(x,v[i],k[i]);
else if(type[x-n]) sol.AddEdge(x,v[i],max(0,k[i]-abs(w[x-n]-w[v[i]])));
else sol.AddEdge(x,v[i],k[i]+abs(w[x-n]-w[v[i]]));
}
}
sol.solve(1);
printf("%d\n",min(sol.d[n],sol.d[n*2]));
return 0;
}
虫洞 (C++)