洛谷P1613 跑路 图论

正解:倍增+图论

解题报告:

传送门!

话说这题是真滴很妙啊,,,大概港下QwQ

首先看懂这道题,它是说,只要是1<<k的都能1s跑过,而且每条边的长度都是1,就是说一秒可以跑过1<<k条边

于是就可以先预处理出只用跑1s的点之间连上边,然后就变成最短路问题辣!

至于怎么预处理只用跑1s的点,就开一个bool数组f[i][j][k]表示i到j能否在2<<k内跑过去,然后转移就很好想了嘛,如果f[i][p][k]&&f[p][j][k]那就能转移到f[i][j][k+1]

话说看到这个转移,可以发现是枚举三个点嘛,于是想到Floyd,于是就没啦!

(,,,听说可以用spfa!好神仙的样子!想学!QAQ!

然后关于最后的求最短路,,,看到题解里都是Floyd或者spfa什么的,,,但是我jio得它都说了每条边长度为1了难道不是暗示用bfs?反正我用的bfsQAQ我我我我也不清楚复杂度QAQ

(还有个玄学事件我要记录下,,,是这样的,本来它是说M<=10000,但是我看N<=50就想着肯定是有重边,我就判了下重边什么的edge数组就开得不大

然后就一直RERERE,我加加加空间加到极大才过得去,,,但我jio得不应该啊我明明特判的重边的?QAQ?

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define mp make_pair
#define rp(i,x,y) for(register ll i=x;i<=y;++i)

const ll N=60,M=500000+100;
ll n,m,head[N],cnt;
bool gg[N][N][65],gdgs=1,vis[N],rd[N][N];
struct ed{ll to,nxt;}edge[M<<2];

inline ll read()
{
    register char ch=getchar();register ll x=0;register bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
    if(ch=='-')ch=getchar(),y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return y?x:-x;
}
inline void ad(int x,int y){edge[++cnt].to=y;edge[cnt].nxt=head[x];head[x]=cnt;}
inline void bfs()
{
    queue< pair<ll,ll> >Q;Q.push(mp(1,0));vis[1]=1;
    while(gdgs)
    {
        ll nw=Q.front().first;ll tm=Q.front().second;Q.pop();
        if(nw==n){printf("%d",tm);return;}
        for(register ll i=head[nw];i;i=edge[i].nxt)
        {if(vis[edge[i].to])continue;Q.push(mp(edge[i].to,tm+1));vis[edge[i].to]=1;}
    }
}

int main()
{
//    freopen("1613.in","r",stdin);
    n=read();m=read();rp(i,1,m){ll x=read(),y=read();gg[x][y][0]=1;ad(x,y);}
    rp(p,1,64)
        rp(k,1,n)
            rp(i,1,n)
                rp(j,1,n)if(gg[i][k][p-1] && gg[k][j][p-1])gg[i][j][p]=1,ad(i,j);
    bfs();
    return 0;
}
放下代码(对了!边的数组开大点!我连续90pts四五次都是RE,数组开小了TT
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值