zoukankan      html  css  js  c++  java
  • 2018多校第三场 hdu6331 M :Walking Plan

    题目链接 hdu6331

    自我吐槽,这场多校大失败,开局签到因输入输出格式写错,wa了3发。队友C题wa了1个小时,还硬说自己写的没错,结果我随便造了个小数据,他都没跑对。然后跑对了后又进入了无限的卡常之中,幸好最后卡过去了。

    G题我头铁写了个单侧凸壳,不对输入数据判重,而是在加入凸壳时判断,结果wa到比赛结束,进而导致I没时间写。M题开局看错题意直接丢了。最后从30多名掉到了150。这大概就是菜得安详吧 ̄ω ̄=

    题意

    给定n个点m条有向边,q次查询,每次查询问走至少k条边的,s到t的最短路径的长度,边可以重复走。

    q=100000,n=50,m<=10000,k<=10000..

    这题用矩阵快速幂啥的复杂度爆炸

    细节

    1.首先最基本的,要先对边去重留下最短边。

    2.这里有个细节要注意一下,在某些情况下 s 到t距离,只有在走过的边数达到某个周期后才有解。

    比如n个点组成一条有向环,则1到2距离只有在走过数边数k=1,n+1,2n+1  。周期也就是环的长度。

    所以查询k时,答案的路径边数范围会在k到n+k之间。

    3.任意两点的最短距离的边数小于n

    预处理

    首先预处理两个数组。g[k][s][t] 代表恰好走k条边后s到t的最短路径。

    k=1,2,……10000.

    这个用Floyd跑全部数据复杂度要k*n*n*n=12.5亿=GG。  这显然是不行的,所以只能分块,我取块长为100,即只让k=1,2,3,……100。但相邻二维数组之间间隔100条边。则复杂降低至1250万。

    接着就是怎么处理块内了。

    dis[k][s][t] 代表走大于等于k条边后s到t的最短路径。

    k=1,2,……100 。

     这个处理方式时先用floyd跑到k=200, 再逆向for 令dis[k][s][t]=min(dis[k][s][t],dis[k+1][s][t])这样就能保证在k=1,2,3……100时答案是正确的。

    因为大于等于k的最坏情况,就是从s到达了点z,接着还要跑(z,t)之间的最短路才能到达t. 而最短路D的边数最多就n-1。 其实更新n项后就一定就正确了。所以溢出100项,只是写的顺手。

    查询

    对于k<=100的查询我们可以直接用dis数组回答复杂度O(1)

    对于k>100的查询,令 k=q*100+r   其中1<=r<=100

    则答案就是min(g[q][s][z]+dis[r][z][t])   。其中z是我们枚举的中间点。 这样就能保证查询到的答案是大于等于k的,且答案是正确的。单次查询复杂度O(n)

    AC代码

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<string.h>
      4 #include<algorithm>
      5 using namespace std;
      6 int dis[202][52][52];
      7 int g[102][52][52];
      8 int INF=1e9,n;
      9 int get(int s,int t,int k)
     10 {
     11     if(k<=100)
     12     {
     13         return dis[k][s][t];
     14     }
     15     else
     16     {
     17         register int i,q,r,ans=INF;
     18 
     19         q=(k-1)/100;
     20         r=k-100*q;
     21         //printf("%d %d 
    ",q,r);
     22         for(i=1; i<=n; i++)
     23         {
     24             ans=min(ans,dis[r][s][i]+g[q][i][t]);
     25         }
     26         return ans;
     27     }
     28 }
     29 int main()
     30 {
     31     int m,t,x,y,w,q,ans;
     32     register int i,j,k,l;
     33     scanf("%d",&t);
     34     while(t--)
     35     {
     36         scanf("%d%d",&n,&m);
     37         memset(dis,63,sizeof(dis));
     38         memset(g,63,sizeof(g));
     39         INF=dis[0][0][0];
     40         //   printf("%d
    ",INF);
     41         for(i=1; i<=n; i++)
     42         {
     43             for(j=1; j<=n; j++)
     44             {
     45                 dis[1][i][j]=INF;
     46             }
     47         }
     48         while(m--)
     49 
     50         {
     51             scanf("%d%d%d",&x,&y,&w);
     52             dis[1][x][y]=min(dis[1][x][y],w);
     53         }
     54         for(i=2; i<=200; i++)
     55         {
     56             for(j=1; j<=n; j++)
     57             {
     58                 for(k=1; k<=n; k++)
     59                 {
     60                     for(l=1; l<=n; l++)
     61                     {
     62                         dis[i][j][k]=min( dis[i][j][k],dis[i-1][j][l]+dis[1][l][k]);
     63                     }
     64                 }
     65             }
     66         }
     67         for(i=1; i<=n; i++)
     68         {
     69             for(j=1; j<=n; j++)
     70             {
     71                 g[1][i][j]=dis[100][i][j];
     72             }
     73         }
     74         for(i=2; i<=100; i++)
     75         {
     76             for(j=1; j<=n; j++)
     77             {
     78                 for(k=1; k<=n; k++)
     79                 {
     80                     for(l=1; l<=n; l++)
     81                     {
     82                         g[i][j][k]=min( g[i][j][k],g[i-1][j][l]+g[1][l][k]);
     83                     }
     84                 }
     85             }
     86         }
     87         for(i=199; i>=1; i--)
     88         {
     89             for(j=1; j<=n; j++)
     90             {
     91                 for(k=1; k<=n; k++)
     92                 {
     93                     dis[i][j][k]=min( dis[i][j][k],dis[i+1][j][k]);
     94                 }
     95             }
     96         }
     97         scanf("%d",&q);
     98         while(q--)
     99         {
    100             scanf("%d%d%d",&x,&y,&k);
    101             ans=get(x,y,k);
    102             if(ans<=INF/10)
    103             {
    104                 printf("%d
    ",ans);
    105             }
    106             else
    107             {
    108                 puts("-1");
    109             }
    110         }
    111     }
    112 
    113     return 0;
    114 }
    HDU6331

    话说我写的这么暴力,在ac代码里居然不算很慢的︿( ̄︶ ̄)︿

  • 相关阅读:
    LeetCode Array Easy 1. Two Sum
    关于VS2015 发布.net mvc 网站失败的问题
    2016计蒜之道复赛 百度地图的实时路况 floyd+cdq分治
    2016计蒜之道复赛 菜鸟物流的运输网络 网络流EK
    HDU5715 XOR 游戏 二分+字典树+dp
    HDU5697 刷题计划 dp+最小乘积生成树
    codeforces 687D Dividing Kingdom II 带权并查集(dsu)
    codeforces 687C
    codeforces 687B
    HDU 5693 D Game 区间dp
  • 原文地址:https://www.cnblogs.com/qswg/p/9394217.html
Copyright © 2011-2022 走看看