「NOIP模拟赛」虫洞
「题目描述」
N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。
- 从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。
- 从黑洞跃迁到白洞,消耗的燃料值增加delta。
- 路径两端均为黑洞或白洞,消耗的燃料值不变化。
作为压轴题,自然不会是如此简单的最短路问题,所以每过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的路线。
题解
首先每个点拆成黑白点
本来一个黑到一个白连边v+delta
但是因为每秒会变色,所以是一个黑到一个黑连边v+delta
条件是俩点的初始颜色不同
其余的同理
然后最短路。。。
一开始spfa写错只有80分好伤心。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define ll long long using namespace std; inline int read() { char ch=getchar(); int f=1,x=0; while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();} return x*f; } int n,m,cnt; int q[10005];ll d[10005]; bool mp[10005],inq[10005]; int w[10005],s[10005]; int h[10005],head[10005]; struct data{int to,next,v;}ed[100005],e[200005]; void ins(int u,int v,int w) {ed[++cnt].to=v;ed[cnt].v=w;ed[cnt].next=h[u];h[u]=cnt;} void insert(int u,int v,int w) {e[++cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;} void build(int x) { insert(x,x+n,s[x]); insert(x+n,x,0); for(int i=h[x];i;i=ed[i].next) { int de=abs(w[x]-w[ed[i].to]); if(mp[x]!=mp[ed[i].to]) { insert(x,ed[i].to,ed[i].v+de); insert(x+n,ed[i].to+n,max(0,ed[i].v-de)); } else { insert(x,ed[i].to+n,ed[i].v); insert(x+n,ed[i].to,ed[i].v); } } } void spfa() { int t=0,w=1; memset(d,127,sizeof(d)); if(mp[1]){q[0]=1;d[1]=0;inq[1]=1;} else {q[0]=n+1;d[n+1]=0;inq[n+1]=1;} while(t!=w) { int now=q[t];t++;if(t==10001)t=0; for(int i=head[now];i;i=e[i].next) { if(e[i].v+d[now]<d[e[i].to]) { d[e[i].to]=d[now]+e[i].v; if(!inq[e[i].to]) { inq[e[i].to]=1; q[w++]=e[i].to; if(w==10001)w=0; } } } inq[now]=0; } printf("%I64d",min(d[n],d[n+n])); } int main() { //freopen("holes.in","r",stdin); //freopen("holes.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) mp[i]=read(); for(int i=1;i<=n;i++) w[i]=read(); for(int i=1;i<=n;i++) s[i]=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(),w=read(); ins(u,v,w); } cnt=0; for(int i=1;i<=n;i++) build(i); spfa(); return 0; } |