zoukankan      html  css  js  c++  java
  • 【JZOJ4893】【NOIP2016提高A组集训第15场11.14】过河

    题目描述

    这里写图片描述

    数据范围

    这里写图片描述

    解法

    由于同一个点,同一个圆盘最多只会走一次。
    把(i,j)当作一个点,表示第i个点,放第i个圆盘。
    那么就可以使用最短路。
    时间复杂度为O(n4k)
    事实上存在冗余圆盘,一个相对某个圆盘又贵又小的圆盘即是冗余圆盘。


    给圆盘排序,那么令(i,j)只给(k,l)连一条边使得l最小,(i,j)给(i,j+1)连一条边。
    那么任意一条原图中的边就可以分解为上述两类边。
    那么边数就降到n3
    spfa的时间复杂度为O(n3k)
    如果使用dijstra的时间复杂度为O(n3logn)

    代码

    Const
            maxn=257;
    Type
            longint=cardinal;
    Var
            t,n,m,w,i,j,k,l:cardinal;
            dis:array[1..maxn,1..maxn] of longint;
            bz:array[1..maxn,1..maxn] of boolean;
            a:array[1..maxn,0..1] of longint;
            b:array[0..maxn,0..1] of longint;
            c:array[0..maxn*maxn*maxn,0..1] of word;
            ban:array[1..maxn] of boolean;
            d:array[0..maxn] of longint;
            head,tail:longint;
            ans:longint;
            path:array[1..maxn,1..maxn,1..maxn] of word;
            fi:array[1..maxn,1..maxn] of longint;
            la:array[1..maxn*maxn*maxn] of longint;
            ne:array[1..maxn*maxn*maxn] of longint;
            cnt,tot:longint;
            x,y,z:longint;
    Function min(a,b:longint):longint;
    begin
            if (a>b) then exit(b);
            exit(a);
    end;
    Procedure add_line(a,b,c:longint);
    begin
            inc(tot);
            ne[tot]:=fi[a][b];
            la[tot]:=c;
            fi[a][b]:=tot;
    end;
    Procedure add(x,y,z:longint);
    begin
            if (dis[x][y]>z) then
            begin
                    dis[x][y]:=z;
                    if (z<ans) and (bz[x][y]=false) then
                    begin
                            inc(tail);
                            c[tail][0]:=x;
                            c[tail][1]:=y;
                            bz[x][y]:=true;
                            if (head<tail) and (dis[c[head+1][0]][c[head+1][1]]>dis[c[tail][0]][c[tail][1]]) then
                            begin
                                    c[0]:=c[tail];
                                    c[tail]:=c[head+1];
                                    c[head+1]:=c[0];
                            end;
                    end;
            end;
    end;
    Procedure qsort(l,r:longint);
    var
            i,j,k,mid,mm,tmp:longint;
    begin
            i:=l;
            j:=r;
            mid:=b[(l+r) div 2][0];
            repeat
                    while (b[i][0]<mid) do inc(i);
                    while (b[j][0]>mid) do dec(j);
                    if (i<=j) then
                    begin
                            b[0]:=b[i];
                            b[i]:=b[j];
                            b[j]:=b[0];
                            dec(j);
                            inc(i);
                    end;
            until i>j;
            if (i<r) then qsort(i,r);
            if (l<j) then qsort(l,j);
    end;
    Function judge(i,j,k,l:longint):boolean;
    begin
            exit(int64(a[i][0]-a[j][0])*(a[i][0]-a[j][0])+(a[i][1]-a[j][1])*(a[i][1]-a[j][1])<=int64(b[l][0]+b[k][0])*(b[l][0]+b[k][0]));
    end;
    Procedure extreme;
    begin
            qsort(1,m);
            for i:=1 to n do
                    for j:=1 to n do
                    begin
                            l:=1;
                            for k:=m downto 1 do
                            begin
                                    while (l<=m) do
                                    begin
                                            if (judge(i,j,k,l)) then
                                            begin
                                                    path[i][k][j]:=l;
                                                    break;
                                            end
                                            else inc(l);
                                    end;
                                    if (path[i][k][j]>0) then add_Line(i,k,j);
                            end;
                    end;
    end;
    Procedure spfa;
    var
            i,j,k:cardinal;
    Begin
            while (head<tail) do
            begin
                    inc(head);
                    if (c[head][1]<m) then
                    begin
                            add(c[head][0],c[head][1]+1,dis[c[head][0]][c[head][1]]+b[c[head][1]+1][1]-b[c[head][1]][1]);
                    end;
                    k:=fi[c[head][0]][c[head][1]];
                    while (k>0) do
                    begin
                            i:=la[k];
                            j:=path[c[head][0]][c[head][1]][i];
                            add(i,j,dis[c[head][0]][c[head][1]]+b[j][1]);
                            k:=ne[k];
                    end;
                    if (a[c[head][0]][1]+b[c[head][1]][0]>=w) then ans:=min(dis[c[head][0]][c[head][1]],ans);
                    bz[c[head][0]][c[head][1]]:=false;
            end;
    End;
    Procedure prepare;
    begin
            readlN(n,m,w);
            for i:=1 to n do
            begin
                    readln(a[i][0],a[i][1]);
            end;
            for i:=1 to m do
            begin
                    readln(b[i][0],b[i][1]);
            end;
            fillchar(ban,sizeof(ban),0);
            for i:=1 to m do for j:=i+1 to m do
                    if (b[i][0]>=b[j][0]) and (b[i][1]<=b[j][1]) then ban[j]:=true
                    else if (b[i][0]<=b[j][0]) and (b[i][1]>=b[j][1]) then ban[i]:=true;
            d[0]:=0;
            for i:=1 to m do if (ban[i]=false) then
            begin
                    inc(d[0]);
                    d[d[0]]:=i;
            end;
            for i:=1 to d[0] do b[i]:=b[d[i]];
            m:=d[0];
            fillchar(dis,sizeof(dis),127);
            fillchar(path,sizeof(path),0);
            fillchar(fi,sizeof(fi),0);
            tot:=0;
            head:=0;
            tail:=0;
            ans:=maxlongint;
            extreme;
            for i:=1 to n do
                    for j:=1 to m do
                    begin
                            if (b[j][0]>=a[i][1]) then
                            begin
                                    add(i,j,b[j][1]);
                                    break;
                            end;
                    end;
    end;
    Procedure getans;
    begin
            if (ans<2000000000) then writeln(ans)
            else writeln('impossible');
    end;
    Begin
            assign(input,'river.in');reset(input);
            assign(output,'river.out');rewrite(output);
            readln(t);
            for t:=1 to t do
            begin
                    prepare;
                    spfa;
                    getans;
            end;
            //writeln(cnt);
            close(output);close(input);
    End.

    启发

    去除冗余

    差分

    本题中:原图共有n4,考虑到如果(i,j)可以到达(k,l),那么(i,j)也一定可以到达(k,l’),其中l’的半径比l大。如果存在这样的关系:
    这里写图片描述
    并且dis[x][z]=dis[y][z]+dis[x][y]
    那么(x,z)这条边显然可以省略。
    当大量存在这样的边时,如本题,就可以优化边数。

    spfa优化

    1.SFL优化
    

    尽量维持决策遍历队列的单调性,这样可以使得以更高的频率用更优的点更新。
    具体而言,如果dis[b[head+1]]>dis[b[tail]],则swap(b[head+1],b[tail])。

    2.单点最短路优化
    

    由于spfa自带求单源到所有点的最短路,如果我们只需要求单源到单汇的最短路,那么显然如果当前节点比目标节点更劣就直接跳过。

  • 相关阅读:
    upc组队赛1 黑暗意志【stl-map】
    upc组队赛1 闪闪发光 【优先队列】
    upc组队赛1 流连人间的苏苏
    POJ 2387 Til the Cows Come Home 【最短路SPFA】
    POJ 2421 Constructing Roads 【最小生成树Kruscal】
    qrcode-使用
    submlie 配置php运行
    composer 安装laravel
    composer 配置镜像
    Laravel-队列
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714833.html
Copyright © 2011-2022 走看看