zoukankan      html  css  js  c++  java
  • 拆点:虫洞

    题目描述 
    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]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 100 10 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, 1<=u,v<=N, k,w[i],s[i]<=200 
    其中 20%的数据为  1<=N<=3000 的链 
    样例解释 1->3 ->4

     

    每个点有两种状态,白洞、黑洞
    若由白洞到黑洞,到达黑洞时,黑洞已变为白洞。
    若由黑洞到白洞,到达白洞时,白洞已变为黑洞。
    所以,可以将一个点拆分为两个点,分别在两个平面内,上层为原来的状态,下层为相反的状态。
    若有边i,j,权值为t,从上层i到下层j连一条边,从下层i到上层j连一条边。
    且由上层i到下层j连一条边。
    权值分别计算。
    起点为上层1,最后结果为下层n,上层n的最小值。

    通过spfa计算。

    可以采用循环队列。


    code:

    var n,m:longint;
    w,s,stay:array[1..10000]of longint;
    edge:array[1..100000]of record
    x,y,z:longint;
    end;
    num1,num2:array[1..10000]of longint;
    i,j,k:longint;
    num:longint;
    x,y,z:longint;
    queue:array[0..100000]of longint;
    dist:array[1..10000]of longint;
    head,tail:longint;
    ans:longint;
    used:array[1..10000]of boolean;
    function max(x,y:longint):longint;
    begin if x>y
    then exit(x)
    else exit(y);
    end;
    function min(x,y:longint):longint;
    begin if x>y
    then exit(y)
    else exit(x);
    end;
    procedure qsort(x,y:longint);
    var head,tail,k,temp:longint;
    begin head:=x; tail:=y;
    k:=edge[(head+tail) div 2].x;
    while head<tail do
    begin while edge[head].x<k do inc(head);
    while k<edge[tail].x do dec(tail);
    if head<=tail
    then begin temp:=edge[head].x;
    edge[head].x:=edge[tail].x;
    edge[tail].x:=temp;
    temp:=edge[head].y;
    edge[head].y:=edge[tail].y;
    edge[tail].y:=temp;
    temp:=edge[head].z;
    edge[head].z:=edge[tail].z;
    edge[tail].z:=temp;
    inc(head);
    dec(tail);
    end;
    end;
    if head<y then qsort(head,y);
    if x<tail then qsort(x,tail);
    end;
    begin 
    readln(n,m);
    for i:=1 to n do
    read(s[i]);
    for i:=1 to n do
    read(w[i]);
    for i:=1 to n do
    read(stay[i]);
    num:=0;
    for i:=1 to m do
    begin readln(x,y,z);
    inc(num);
    edge[num].x:=x;
    edge[num].y:=y+n;
    if s[x]=s[y]
    then edge[num].z:=z;
    if (s[x]=1)and(s[y]=0)
    then edge[num].z:=z+abs(w[x]-w[y]);
    if (s[x]=0)and(s[y]=1)
    then edge[num].z:=max(0,z-abs(w[x]-w[y]));
    inc(num);
    edge[num].x:=x+n;
    edge[num].y:=y;
    if s[x]=s[y]
    then edge[num].z:=edge[num-1].z;
    if (s[x]=1)and(s[y]=0)
    then edge[num].z:=max(0,z-abs(w[x]-w[y]));
    if (s[x]=0)and(s[y]=1)
    then edge[num].z:=z+abs(w[x]-w[y]);
    end;
    for i:=1 to n do
    begin if s[i]=1
    then begin inc(num);
    edge[num].x:=i;
    edge[num].y:=i+n;
    edge[num].z:=stay[i];
    inc(num);
    edge[num].x:=i+n;
    edge[num].y:=i;
    edge[num].z:=0;
    end;
    if s[i]=0
    then begin inc(num);
    edge[num].x:=i;
    edge[num].y:=i+n;
    edge[num].z:=0;
    inc(num);
    edge[num].x:=i+n;
    edge[num].y:=i;
    edge[num].z:=stay[i];
    end;
    end;
    qsort(1,num);
    for i:=1 to 2*n do
    begin num1[i]:=maxlongint;
    num2[i]:=0;
    end;
    for i:=num downto 1 do
    begin inc(num2[edge[i].x]);
    if i<num1[edge[i].x]
    then num1[edge[i].x]:=i;
    end;
          fillchar(used,sizeof(used),true);
    for i:=1 to 2*n do
    dist[i]:=maxint*500;
    head:=0; tail:=0;
    queue[head]:=1;
    dist[1]:=0;
    while head<>tail+1 do
    begin for i:=1 to num2[queue[head]] do
    begin if (dist[queue[head]]+edge[num1[queue[head]]+i-1].z<
    dist[edge[num1[queue[head]]+i-1].y])
    then begin dist[edge[num1[queue[head]]+i-1].y]:=
    dist[queue[head]]+edge[num1[queue[head]]+i-1].z;
    if (used[edge[num1[queue[head]]+i-1].y])
    then begin tail:=(tail+1) mod (2*n) ;
    queue[tail]:=edge[num1[queue[head]]+i-1].y;
    used[edge[num1[queue[head]]+i-1].y]:=false;
    end;
    end;
    end;
    used[queue[head]]:=true;
    head:=(head+1) mod (2*n);
    end;
    ans:=min(dist[n],dist[2*n]);
    writeln(ans);
    end.
     
  • 相关阅读:
    css3 的box-sizing属性理解
    web自定义炫酷字体
    Canvas rontate(旋转) 使用误区
    HTM5 之 Canvas save 、restore 恢复画布状态的理解
    Canvas的quadraticCurveTo 和 bezierCurveTo 画曲线 方法细说
    关于EF的一点小记录
    IIS 发布webservice 需要用户名和密码访问 解决
    【算法笔记】A1060 Are They Equal
    【算法笔记】A1063 Set Similarity
    【算法笔记】B1052 卖个萌
  • 原文地址:https://www.cnblogs.com/spiderKK/p/4912241.html
Copyright © 2011-2022 走看看