BZOJ 4070:[APIO2015]雅加达的摩天楼 最短路

4070: [Apio2015]雅加达的摩天楼

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 464  Solved: 164
[Submit][Status][Discuss]

Description

 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1。除了这 N 座摩天楼外,雅加达市没有其他摩天楼。

 
有 M 只叫做 “doge” 的神秘生物在雅加达市居住,它们的编号依次是 0 到 M−1。编号为 i 的 doge 最初居住于编号为 Bi 的摩天楼。每只 doge 都有一种神秘的力量,使它们能够在摩天楼之间跳跃,编号为 i 的 doge 的跳跃能力为 Pi (Pi>0)。
 
在一次跳跃中,位于摩天楼 b 而跳跃能力为 p 的 doge 可以跳跃到编号为 b−p (如果 0≤b−p<N)或 b+p (如果 0≤b+p<N)的摩天楼。
 
编号为 0 的 doge 是所有 doge 的首领,它有一条紧急的消息要尽快传送给编 号为 1 的 doge。任何一个收到消息的 doge 有以下两个选择:
 
跳跃到其他摩天楼上;
将消息传递给它当前所在的摩天楼上的其他 doge。
请帮助 doge 们计算将消息从 0 号 doge 传递到 1 号 doge 所需要的最少总跳跃步数,或者告诉它们消息永远不可能传递到 1 号 doge。
 

Input

输入的第一行包含两个整数 N 和 M。

 
接下来 M 行,每行包含两个整数 Bi 和 Pi。
 

Output

输出一行,表示所需要的最少步数。如果消息永远无法传递到 1 号 doge,输出 −1。

 

Sample Input

5 3
0 2
1 1
4 1

Sample Output

5
explanation
下面是一种步数为 5 的解决方案:
0 号 doge 跳跃到 2 号摩天楼,再跳跃到 4 号摩天楼(2 步)。
0 号 doge 将消息传递给 2 号 doge。
2 号 doge 跳跃到 3 号摩天楼,接着跳跃到 2 号摩天楼,再跳跃到 1 号摩天楼(3 步)。
2 号 doge 将消息传递给 1 号 doge。

HINT

 

 子任务


所有数据都保证 0≤Bi<N。

 

子任务 1 (10 分)

1≤N≤10

1≤Pi≤10

2≤M≤3

子任务 2 (12 分)

1≤N≤100

1≤Pi≤100

2≤M≤2000

子任务 3 (14 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤2000

子任务 4 (21 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤30000

子任务 5 (43 分)

1≤N≤30000

1≤Pi≤30000

2≤M≤30000

 

Source

 

想法:因为同一个doge不会再跑回来,所以这样暴力连边:Bi->Bi+k*Pi dis=k;K∈N.O(n^2)

另一个暴力:每种P,对于每种模数[0,P-1]。建一条轨道,轨道之间连双向边边权为1.然后Bi直接连Bi对应的轨道点P,边权为0.O(n^2)

优化第二个暴力:如果这个模数上并没有点那就不用建了。

分析一发复杂度:最坏情况,那肯定是所有轨道上都只有一个点。模数越大,一个点要建的轨道越小:N/P。所以最坏数据P从1开始,每个模数都有一个。

M=1+2+3+...+X。X=sqrt (2*M) 所以共O(sqrt(2*M)*n)条边...理论复杂度过了,但也许需要卡卡空间.....

#include<cstdio>
#include<vector>
#include<algorithm>

#define usint unsigned short int 
#define next(x) x==M?1:x+1
#define swap(a,b) a^=b,b^=a,a^=b;
//1<<16 -1
const int len(30000),N(7333654),INF(0x7fffffff),M(733365);
int n,m,now,S,T,last[len+10];
struct Data{usint B,P,k;}doge[len+10];
bool cmp(Data X,Data Y){if(X.P==Y.P)return X.k<Y.k;return X.P<Y.P;}
struct Node{int nd,nx;}bot[len+10];
int tot,first[len+10],Down[N+10],Up[N+10];//卡空间 
usint To[N+10];
void add(int a,int b){bot[++tot]=(Node){b,first[a]};first[a]=tot;}
template <class T>void read(T &x)
{
    x=0; char ch=getchar(); int f=0;
    while(ch<'0'||ch>'9'){f=(ch=='-');ch=getchar();} 
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    x=f?-x:x;
}
int q[M+10],l,h,x,y; int dis[N+10]; bool flag[N+10];
void Spfa()
{
    for(int i=0;i<=now;i++)dis[i]=INF;//dis[0]=0;
    q[l=1]=S; dis[S]=0; h=0; flag[S]=1;
    while(h!=l)
    {
        h=next(h); x=q[h]; y=next(h);
        if(x<=n)
        {
            for(int v=first[x];v;v=bot[v].nx)
            if(dis[bot[v].nd]>dis[x])
            {
                dis[bot[v].nd]=dis[x];
                if(!flag[bot[v].nd])
                {
                    l=next(l);
                    q[l]=bot[v].nd; flag[bot[v].nd]=1;
                    if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]);
                }
            }    
        }else
        {
            if(dis[To[x]]>dis[x])
            {
                dis[To[x]]=dis[x];
                if(!flag[To[x]])
                {
                    l=next(l);
                    q[l]=To[x]; flag[To[x]]=1;
                    if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]);
                }            
            }
            if(dis[Down[x]]>dis[x]+1)
            {
                dis[Down[x]]=dis[x]+1;
                if(!flag[Down[x]])
                {
                    l=next(l);
                    q[l]=Down[x]; flag[Down[x]]=1;
                    if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]);
                }            
            }            
            if(dis[Up[x]]>dis[x]+1)
            {
                dis[Up[x]]=dis[x]+1;
                if(!flag[Up[x]])
                {
                    l=next(l);
                    q[l]=Up[x]; flag[Up[x]]=1;
                    if(dis[q[l]]>dis[q[y]])swap(q[y],q[l]);
                }            
            }
        }
        flag[x]=0;
    }
}
int main()
{
    read(n),read(m);
    for(int i=1;i<=m;i++)
    {
        read(doge[i].B),read(doge[i].P);
        doge[i].k=doge[i].B%doge[i].P;
    }
    S=doge[1].B;T=doge[2].B;
    std::sort(doge+1,doge+1+m,cmp);
    now=n;
    for(int i=1;i<=m;i++)
    {
        if(doge[i].P!=doge[i-1].P || doge[i].k!=doge[i-1].k)
            for(int j=doge[i].k;j<n;j+=doge[i].P)
            {
                To[++now]=j; 
                if(j!=doge[i].k)Down[now]=now-1;else Down[now]=now;
                if(j+doge[i].P<n)Up[now]=now+1;else Up[now]=now;
                last[j]=now;
            }
        add(doge[i].B,last[doge[i].B]);
    }
    Spfa();
    printf("%d",dis[T]!=INF?dis[T]:-1);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Oncle-Ha/p/6683313.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在MATLAB中,NURBS(非均匀有理B样条)是一种强大的数学工具,用于表示和处理复杂的曲线和曲面。NURBS在计算机图形学、CAD(计算机辅助设计)、CAM(计算机辅助制造)等领域有着广泛的应用。下面将详细探讨MATLAB中NURBS的绘制方法以及相关知识点。 我们需要理解NURBS的基本概念。NURBS是B样条(B-Spline)的一种扩展,其特殊之处在于引入了权重因子,使得曲线和曲面可以在不均匀的参数空间中进行平滑插值。这种灵活性使得NURBS在处理非均匀数据时尤为有效。 在MATLAB中,可以使用`nurbs`函数创建NURBS对象,它接受控制点、权值、 knot向量等参数。控制点定义了NURBS曲线的基本形状,而knot向量决定了曲线的平滑度和分布。权值则影响曲线通过控制点的方式,大的权值会使曲线更靠近该点。 例如,我们可以使用以下代码创建一个简单的NURBS曲线: ```matlab % 定义控制点 controlPoints = [1 1; 2 2; 3 1; 4 2]; % 定义knot向量 knotVector = [0 0 0 1 1 1]; % 定义权值(默认为1,如果未指定) weights = ones(size(controlPoints,1),1); % 创建NURBS对象 nurbsObj = nurbs(controlPoints, weights, knotVector); ``` 然后,我们可以用`plot`函数来绘制NURBS曲线: ```matlab plot(nurbsObj); grid on; ``` `data_example.mat`可能包含了一个示例的NURBS数据集,其中可能包含了控制点坐标、权值和knot向量。我们可以通过加载这个数据文件来进一步研究NURBS的绘制: ```matlab load('data_example.mat'); % 加载数据 nurbsData = struct2cell(data_example); % 转换为cell数组 % 解析数据 controlPoints = nurbsData{1}; weights = nurbsData{2}; knotVector = nurbsData{3}; % 创建并绘制NURBS曲线 nurbsObj = nurbs(controlPoints, weights, knotVector); plot(nurbsObj); grid on; ``` MATLAB还提供了其他与NURBS相关的函数,如`evalnurbs`用于评估NURBS曲线上的点,`isoparm`用于生成NURBS曲面上的等参线,以及`isocurve`用于在NURBS曲面上提取特定参数值的曲线。这些工具对于分析和操作NURBS对象非常有用。 MATLAB中的NURBS功能允许用户方便地创建、编辑和可视化复杂的曲线和曲面。通过对控制点、knot向量和权值的调整,可以精确地控制NURBS的形状和行为,从而满足各种工程和设计需求。通过深入理解和熟练掌握这些工具,可以在MATLAB环境中实现高效的NURBS建模和分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值