• 解题报告 幸福的道路


    1.        题目

    幸福的道路(race)

    【问题描述】

    小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.

    他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.

    他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).

     

    【输入格式】

    第一行包含一个整数N.

    第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.

     

    【输出格式】

     

    每天的锻炼路径长度

    【样例输入】

    1 1

    1 3

     

    【样例输出】

    3

    4

    4

     

    数据范围:

     

    50%的数据N<=1000

    80%的数据N<=100 000

    100%的数据N<=1000 000

     

    2.        算法

    第一种方法:用队列优化的树形动规。

     

    还有一种比较纠结的,以前在博客中写过:

    首先说明一个定理,离树中某一个点最远的点,一定是在树的直径(树中距离最远的两个点之间的路径)的一个端点。

    证明:如果存在一个更远的点,不是端点,但是比较远的那个端点距离这个点更远,则此时,距离这个点较近的那个端点可以经过这个点,到达那个更远的点,这样就会找出一条比直径更长的路径。但事实上,直径应该是一个树中最长的路径,所以离树中某一个点最远的点,一定是在树的直径(树中距离最远的两个点之间的路径)的一个端点,证毕。

    然后,这样的话,就可以先求出树的直径的两个端点(从任意一个点开始  BFS ,找到距离他最远的那个点,根据上方定理,这必是一个端点,再从这个已知端点开始 BFS ,找到距离他最远的那个点,显然这就是另一个端点),然后从这两个点开始,走单源最短路。然后求解的时候,只需要找出每一个点距这两个点的距离中的较大的那个,就是答案了。

     

    然后这个题的标准算法是树形动规。

    这个方法太麻烦,而且这是个多叉树,存都不好存,本人没有深入研究,在此引用一下。

    1.题目可以使用搜索做,但是由于数据范围极大,极可能会超时

    2.这样就可以向其他方面思考:题目中给出的是一棵树,就是树形DP

    距离一个节点最远的点  在此节点的子树中 或 在它的父节点的其他子树中

    这样,每一个节点要存储三个信息

        1.在他的子树中离他最远的点到他的距离

        2.在他的子树中离他第二远的点到他的距离

        3.在他的祖先及其出了他本身的子树中里他最远的点到他的距离

    假设F[i][0]是在以i为根的子树的点里离i最远的距离

    F[i][2]是不在以i为根的子树的点离i最远的距离

    显然答案是max(F[i][0] , F[i][2])

    第一种显然一次dfs就搞定了

    而第二个不是很好办..

    所以我们分析一下..得到了这个方程

    F[i][2] = max(F[Parent[i]][2] , F[Parent[i]][0]) + Dist[Parent[i]][i];

    不过显然当如果F[Parent[i]][0]的决策是i的时候是错的..所以我们只要再记

    录一个在以i为根的子树里且第一步决策和F[i][0]不同的点离i的最大值令其为F[i][1]

    if(F[Parent[i]][0] == F[i][0] + Dist[Parent[i]][i])

    F[i][2] = max(F[Parent[i]][2] , F[Parent[i]][1]) + Dist[Parent[i]][i];

    Else F[i][2] = max(F[Parent[i]][2] , F[Parent[i]][0]) + Dist[Parent[i]][i];

     

    4.        代码

    特殊算法 (Leve

    type pointer=^rec;

     rec=record

      num,len:longint;

      next:pointer;

    end;

    var 

     i,j,a1,a2,n,x,y,max:longint;

     link:array[1..10000] of pointer;

     d1,d2:array[1..10000] of longint;

     v:array[1..10000] of boolean;

     q:array[1..1000000] of longint;

     p:pointer;

    procedure spfa1(x:longint);

     var

      i,l,r,temp:longint;

      p:pointer;

     begin

      filldword(d1,sizeof(d1)>>2,maxlongint>>1);

      fillchar(v,sizeof(v),false);

      d1[x]:=0;

      v[x]:=true;

      q[1]:=x;

      l:=0; r:=1;

      while l<r do

       begin

        inc(l);

    temp:=q[l];

    p:=link[temp];

    v[temp]:=false;

    while p<>nil do

     begin

      if d1[p^.num]>d1[temp]+p^.len then

       begin

        d1[p^.num]:=d1[temp]+p^.len;

    if not v[p^.num] then

     begin

      v[p^.num]:=true;

      inc(r);

      q[r]:=p^.num;

     end;

       end;

      p:=p^.next;

     end;

      end;

     end; 

    procedure spfa2(x:longint);

     var

      i,l,r,temp:longint;

      p:pointer;

     begin

      filldword(d2,sizeof(d2)>>2,maxlongint>>1);

      fillchar(v,sizeof(v),false);

      d2[x]:=0;

      v[x]:=true;

      q[1]:=x;

      l:=0; r:=1;

      while l<r do

       begin

        inc(l);

    temp:=q[l];

    p:=link[temp];

    v[temp]:=false;

    while p<>nil do

     begin

      if d2[p^.num]>d2[temp]+p^.len then

       begin

        d2[p^.num]:=d2[temp]+p^.len;

    if not v[p^.num] then

     begin

      v[p^.num]:=true;

      inc(r);

      q[r]:=p^.num;

     end;

       end;

      p:=p^.next;

     end;

      end;

     end;

    begin

     assign(input,'length.in');

     assign(output,'length.out');

     reset(input);

     rewrite(output);

     readln(n);

     for i:=2 to n do

      begin

       read(x,y);

       new(p);

       p^.num:=x;

       p^.len:=y;

       p^.next:=link[i];

       link[i]:=p;

       new(p);

       p^.num:=i;

       p^.len:=y;

       p^.next:=link[x];

       link[x]:=p;

      end;

     spfa1(1);

     max:=0;

     for i:=1 to n do

     if d1[i]<maxlongint>>1 then

      if d1[i]>max then

       begin

       max:=d1[i];

       a1:=i;

      end;

     spfa1(a1);

     max:=0;

     for i:=1 to n do

     if d1[i]<maxlongint>>1 then

      if d1[i]>max then

       begin

       max:=d1[i];

       a2:=i;

      end;

     spfa2(a2);

     for i:=1 to n do

      begin

       if d1[i]=maxlongint>>1 then d1[i]:=0;

       if d2[i]=maxlongint>>1 then d2[i]:=0;

      end;

     for i:=1 to n do

      if d1[i]>d2[i] then

       writeln(d1[i])

      else

      writeln(d2[i]);

     close(input);

     close(output);

    end.

       

     

     

     

     

     

    树形动规 (std

    program length;

    type

      edge=record

        x,w,next:longint;

      end;

    var

      e,e2:array[0..200000]of edge;

      k,k2:array[0..10000]of longint;

      fa:array[0..10000]of longint;

      w:array[0..10000]of longint;

      tot,tot2,i,j,n,x,y:longint;

      v:array[0..10000]of boolean;

      f:array[0..10000,0..2]of longint;

    function max(a,b:longint):longint;

      begin

        if (a>b) then exit(a) else exit(b);

      end;

    procedure add2(a,b,c:longint);

      begin

        inc(tot2);

        e2[tot2].x:=b;

        e2[tot2].w:=c;

        e2[tot2].next:=k2[a];

        k2[a]:=tot2;

      end;

    procedure add(a,b,c:longint);

      begin

        inc(tot);

        e[tot].x:=b;

        e[tot].w:=c;

        e[tot].next:=k[a];

        k[a]:=tot;

      end;

    procedure build(x:longint);

      var

        t:longint;

      begin

        v[x]:=true;

        t:=k2[x];

        while (t<>0) do

          begin

            if (not v[e2[t].x]) then

              begin

                fa[e2[t].x]:=x;

                w[e2[t].x]:=e2[t].w;

                add(x,e2[t].x,e2[t].w);

                build(e2[t].x);

              end;

            t:=e2[t].next;

          end;

      end;

    procedure dp_down(x:longint);

      var

        t:longint;

      begin

        t:=k[x];

        while (t<>0) do

          begin

            dp_down(e[t].x);

            if (f[e[t].x][1]+e[t].w>f[x][1]) then

              begin

                f[x][2]:=f[x][1];

                f[x][1]:=f[e[t].x][1]+e[t].w;

              end

              else

            if (f[e[t].x][1]+e[t].w>f[x][2]) then

              begin

                f[x][2]:=f[e[t].x][1]+e[t].w;

              end;

            t:=e[t].next;

          end;

      end;

    procedure dp_up(x:longint);

      var

        t:longint;

      begin

        if (fa[x]<>0) then

          begin

            if (f[fa[x]][1]=f[x][1]+w[x]) then

              f[x][0]:=max(f[fa[x]][2],f[fa[x]][0])+w[x]

            else f[x][0]:=max(f[fa[x]][1],f[fa[x]][0])+w[x];

          end;

        t:=k[x];

        while (t<>0) do

          begin

            dp_up(e[t].x);

            t:=e[t].next;

          end;

      end;

    begin

      assign(input,'length.in');reset(input);

      assign(output,'length.out');rewrite(output);

      readln(n);

      for i:=2 to n do

        begin

          readln(x,y);

          add2(i,x,y);

          add2(x,i,y);

        end;

      build(1);

      dp_down(1);

      dp_up(1);

      for i:=1 to n do

        begin

          writeln(max(f[i][0],f[i][1]));

        end;

      close(input);

      close(output);

    end.

     

     

    PS:这是这个题的化简版,原题:

           

    【问题描述】

     

    小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.

     

    他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.

     

    他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).

     

    他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M(即一段连续的区间并且区间的最大值最小值之差不超过M).他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?

     

    现在,他们把这个艰巨的任务交给你了!

     

     

     

    【输入格式】

     

    第一行包含两个整数N, M(M<=10^9).

     

    第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.

     

     

     

    【输出格式】

     

    最长的连续锻炼天数

     

     

     

    【样例输入】

     

    3 2

     

    1 1

     

    1 3

     

     

     

    【样例输出】

     

    3

     

     

     

    数据范围:

     

     

     

    50%的数据N<=1000

     

    80%的数据N<=100000

     

    100%的数据N<=1000 000

     

     

    然后,求出来每天锻炼路径之后,最长连续锻炼天数怎么快速的求出来。。。。才疏学浅,三个点超时。

    这是那个 70 的代码。。。。写得好烂。。。。

    代码:(SueMiller)

    program ACRush;
    var a:array[0..2000010,1..3]of longint;
        dist1,dist2,dist3:array[0..1000010]of longint;
        t,arr:array[0..1000010]of longint;
        q:array[0..10000010]of longint;
        vq:array[0..1000010]of boolean;
        i,j,k,d1,d2:longint;
        n,m,tot,maxx,minn,l,r,ans,tempn,tempx:longint;

    procedure quicksort(l,r:longint);
    var x,i,j:longint;
    begin
     i:=l; j:=r; x:=a[(l+r)>>1,1];
     repeat
      while a[i,1]<x do inc(i);
      while x<a[j,1] do dec(j);
      if i<=j then
       begin
       a[0]:=a[i]; a[i]:=a[j]; a[j]:=a[0];
       inc(i); dec(j);
       end;
     until i>j;
     if l<j then quicksort(l,j);
     if i<r then quicksort(i,r);
    end;

    procedure spfa1(x:longint);
    begin
      l:=0;
      r:=1;
      q[1]:=x;
      filldword(dist1,sizeof(dist1)>>2,maxlongint>>1);
      dist1[x]:=0;
      fillchar(vq,sizeof(vq),false);
      vq[x]:=true;
      while l<r do
        begin
          inc(l);
          for i:=t[q[l]] to tot do
            if a[i,1]<>q[l] then break
            else
              begin
                if dist1[q[l]]+a[i,3]<dist1[a[i,2]] then
                  begin
                    dist1[a[i,2]]:=dist1[q[l]]+a[i,3];
                    if not vq[a[i,2]] then
                      begin
                        inc(r);
                        q[r]:=a[i,2];
                        vq[a[i,2]]:=true;
                      end;
                  end;
              end;

          vq[q[l]]:=false;
        end;
    end;

    procedure spfa2(x:longint);
    begin
      l:=0;
      r:=1;
      q[1]:=x;
      filldword(dist2,sizeof(dist2)>>2,maxlongint>>1);
      dist2[x]:=0;
      fillchar(vq,sizeof(vq),false);
      vq[x]:=true;
      while l<r do
        begin
          inc(l);
          for i:=t[q[l]] to tot do
            if a[i,1]<>q[l] then break
            else
              begin
                if dist2[q[l]]+a[i,3]<dist2[a[i,2]] then
                  begin
                    dist2[a[i,2]]:=dist2[q[l]]+a[i,3];
                    if not vq[a[i,2]] then
                      begin
                        inc(r);
                        q[r]:=a[i,2];
                        vq[a[i,2]]:=true;
                      end;
                  end;
              end;

          vq[q[l]]:=false;
        end;
    end;

    procedure spfa3(x:longint);
    begin
      l:=0;
      r:=1;
      q[1]:=x;
      filldword(dist3,sizeof(dist3)>>2,maxlongint>>1);
      dist3[x]:=0;
      fillchar(vq,sizeof(vq),false);
      vq[x]:=true;
      while l<r do
        begin
          inc(l);
          for i:=t[q[l]] to tot do
            if a[i,1]<>q[l] then break
            else
              begin
                if dist3[q[l]]+a[i,3]<dist3[a[i,2]] then
                  begin
                    dist3[a[i,2]]:=dist3[q[l]]+a[i,3];
                    if not vq[a[i,2]] then
                      begin
                        inc(r);
                        q[r]:=a[i,2];
                        vq[a[i,2]]:=true;
                      end;
                  end;
              end;

          vq[q[l]]:=false;
        end;
    end;

    function max(x,y:longint):longint;
    begin
      if x>y then exit(x) else exit(y);
    end;

    begin
      assign(input,'race.in');reset(input);
      assign(output,'race.out');rewrite(output);

      readln(n,m);
      for i:=1 to n-1 do
        begin
          readln(j,k);
          inc(tot);
          a[tot,1]:=i+1;
          a[tot,2]:=j;
          a[tot,3]:=k;
          inc(tot);
          a[tot,1]:=j;
          a[tot,2]:=i+1;
          a[tot,3]:=k;
        end;

      quicksort(1,tot);
      t[a[1,1]]:=1;
      for i:=2 to tot do
        if a[i,1]<>a[i-1,1] then t[a[i,1]]:=i;

      spfa1(1);

      d1:=0;
      k:=0;
      for i:=1 to n do
        if dist1[i]>k then
          begin
            k:=dist1[i];
            d1:=i;
          end;

      spfa2(d1);

      d2:=0;
      k:=0;
      for i:=1 to n do
        if dist2[i]>k then
          begin
            k:=dist2[i];
            d2:=i;
          end;
      spfa3(d2);

      for i:=1 to n do
        arr[i]:=max(dist2[i],dist3[i]);

      ans:=1;
      for i:=1 to n do
        begin
          l:=i;
          r:=i;
          maxx:=arr[i];
          minn:=arr[i];
          tempn:=arr[i]+1;
          tempx:=arr[i]-1;
          while maxx-minn<=m do
            begin
              dec(l);
              if l=0 then break;
              if arr[l]<minn then
                begin
                  tempn:=minn;
                  minn:=arr[l];
                end
              else
                if arr[l]<tempn then tempn:=arr[l];
              if arr[l]>maxx then
                begin
                  tempx:=maxx;
                  maxx:=arr[l];
                end
              else
                if arr[l]>tempx then tempx:=arr[l];
            end;
          if l<>0 then
            begin
              if arr[l]=maxx then maxx:=tempx;
              if arr[l]=minn then minn:=tempn;
            end;
          inc(l);
          while maxx-minn<=m do
            begin
              inc(r);
              if r>n then break;
              if arr[r]<minn then
                begin
                  tempn:=minn;
                  minn:=arr[r];
                end
              else
                if arr[r]<tempn then tempn:=arr[r];
              if arr[r]>maxx then
                begin
                  tempx:=maxx;
                  maxx:=arr[r];
                end
              else
                if arr[r]>tempx then tempx:=arr[r];
            end;
          if r<>n+1 then
            begin
              if arr[r]=maxx then maxx:=tempx;
              if arr[r]=minn then minn:=tempn;
            end;
          dec(r);
          if r-l+1>ans then ans:=r-l+1;
          if ans=n then break;

          l:=i;
          r:=i;
          maxx:=arr[i];
          minn:=arr[i];
          tempn:=arr[i]+1;
          tempx:=arr[i]-1;
          while maxx-minn<=m do
            begin
              inc(r);
              if r>n then break;
              if arr[r]<minn then
                begin
                  tempn:=minn;
                  minn:=arr[r];
                end
              else
                if arr[r]<tempn then tempn:=arr[r];
              if arr[r]>maxx then
                begin
                  tempx:=maxx;
                  maxx:=arr[r];
                end
              else
                if arr[r]>tempx then tempx:=arr[r];
            end;
          if r<>n+1 then
            begin
              if arr[r]=maxx then maxx:=tempx;
              if arr[r]=minn then minn:=tempn;
            end;
          dec(r);
          while maxx-minn<=m do
            begin
              dec(l);
              if l=0 then break;
              if arr[l]<minn then
                begin
                  tempn:=minn;
                  minn:=arr[l];
                end
              else
                if arr[l]<tempn then tempn:=arr[l];
              if arr[l]>maxx then
                begin
                  tempx:=maxx;
                  maxx:=arr[l];
                end
              else
                if arr[l]>tempx then tempx:=arr[l];
            end;
          if l<>0 then
            begin
              if arr[l]=maxx then maxx:=tempx;
              if arr[l]=minn then minn:=tempn;
            end;
          inc(l);
          if r-l+1>ans then ans:=r-l+1;
          if ans=n then break;
        end;

      writeln(ans);

      close(input);close(output);
    end.

     

  • 相关阅读:
    ansible 使用密码登录
    shell脚本报错:-bash: xxx: /bin/bash^M: bad interpreter: No such file or directory
    配置永久生效(登陆shell和非登陆shell)、I/O重定向、Here Docunmet 此处文档、管道、tee
    Navicat for PostgreSQL 序列详解
    flask第十五篇——Response
    Centos防火墙及SELINUX关闭
    linux查看网卡信息的几种方法(命令)
    Python之在函数中调用import语句
    python基础_格式化输出(%用法和format用法)
    Python中怎样简单地用一行写if-then语句?
  • 原文地址:https://www.cnblogs.com/SueMiller/p/2213442.html
Copyright © 2020-2023  润新知