luogu_3645: skyscrapers in Jakarta

Jakarta skyscraper

Description meaning of the questions:
  • There \ (N \) skyscrapers, numbered from left to right \ (0 \) to \ (. 1-N \) .
  • There \ (M \) th information transfer member is sequentially numbered \ (0 \) to \ (. 1-M \) . I number of members originally passed in number \ (B_i \) skyscraper, the postman can skip (forward or backward) between skyscrapers, numbered \ (i \) of the transfer member jumping ability is \ (P_i \ ) .
  • When the transfer crew to reach a skyscraper he can perform two operations
    • 1: jump to other Ferris upstairs.
    • 2: the message to other current transfer member of skyscrapers.
  • To eventually numbered \ (0 \) skyscraper information to the number \ (1 \) skyscraper place.
Input formats:
  • The first input line \ (N \) and \ (M \) . \ ((1 \ leq n \ leq 3 * 10 ^ 4,1 \ leq m \ leq 3 * 10 ^ 4) \)
  • Next, the second \ (2 \) to \ (M +. 1 \) , each row comprising two integers \ (B_i \) and \ (P_i \) .
Output formats:
  • Output line, representing the minimum number of steps, if you can not reach the output \ (--1 \) .
Problem-solving ideas:
  • After analyzing the topic can think of is the shortest path for each transfer member can jump away, you can in order to establish the start and end, while the right one.
  • Consider the practice bordered of violence, but if \ (p \) has at an early age, the worst case \ (n ^ 2 \) edges, any shortest path algorithm can not pass.
  • FIG optimization built using the block thought: the \ (n-\) points merged \ (\ sqrt {n} \ ) blocks
    • For \ (P_i \ leq \ sqrt { n} \) transmitting members:
      • For a skyscraper, it took him transformed from a point to a true skyscraper.
      • For each building construction \ (\ sqrt {n} \ ) layers, each with a \ (n-\) points, the first layer represents \ (p = 1 \) and the walk, the second layer represents \ (p = 2 \) and the walk, ..... Where the first \ (0 \) on behalf of the original that point.
      • Then violence plus side. The first \ (I \) layer represents \ (P = i \) case, pitch \ (I \) points interconnected length \ (1 \) side. Then all these auxiliary points connected to the bottom edge.
    • For each \ (P_i> \ sqrt {n } \) in all its points attainable points of \ (0 \) bordered layer.
  • The total number of edges does not exceed \ (N \ sqrt {N} \) .
  • Construction Plan is completed, the shortest run.
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (3e4 + 10)*500;
const int maxm = (3e4 + 10)*500;
int n, m;
int s, t; //起点和终点
int B[maxn], P[maxn]; //起始于B, 跳跃能力为P
int block;

int head[maxn], nex[maxn<<1], ver[maxn<<1], edge[maxn<<1], tot;
inline void add_edge(int x, int y, int z)
{
    ver[++tot] = y; edge[tot] = z;
    nex[tot] = head[x]; head[x] = tot;
}

inline int get_block(int x, int y){
    return x*n + y;
}

int dist[maxn];
bool v[maxn];
void SPFA()
{
    memset(dist, 0x3f, sizeof(dist));
    dist[s] = 0; queue<int> q;
    q.push(s); v[s] = 1;

    while(q.size())
    {
        int x = q.front(); q.pop();
        v[x] = 0;

        for(int i = head[x]; i; i = nex[i])
        {
            int y = ver[i], z = edge[i];
            if(dist[y] > dist[x] + z)
            {
                dist[y] = dist[x] + z;
                if(!v[y])
                {
                    q.push(y);
                    v[y] = 1;
                }
            }
        }
    }
    printf("%d\n", dist[t] == 0x3f3f3f3f ? -1 : dist[t]);
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1, x, y; i <= m; i++)
    {
        scanf("%d%d", &x, &y);
        B[i] = x + 1, P[i] = y;
    }
    
    //起始位置 终止位置 块的大小
    s = B[1], t = B[2]; block = min((int)sqrt(n), 100);
    
    //每一个点转化为一栋楼, 有sqrt(n)层 
    for(int i = 1; i <= block; i++)
        for(int j = 1; j <= n; j++)
    {
        add_edge(get_block(i, j), j, 0); //楼底到每一层连边
        if(j <= n - i) //j条一次跳出范围了
        {
            //每一层间隔为i的点 跳一次边权为1
            add_edge(get_block(i,j), get_block(i,j)+i, 1);
            add_edge(get_block(i,j)+i, get_block(i,j), 1);
        }
    }
    
    for(int i = 1; i <= m; i++) //考虑每一个doge的跳跃能力
    {
        // 对于每一个传递员, 从楼底到Pi层对应连边
        if(P[i] <= block)
            add_edge(B[i], get_block(P[i], B[i]), 0); 
        else
        {   //如果大于一个块了 那就暴力加边 因为有sqrt个块 所以加sqrt条边
            for(int j = 1; B[i] + j * P[i] <= n; j++)
                add_edge(B[i], B[i] + j*P[i], j); //向前跳
            for(int j = 1; B[i] - j * P[i] >= 1; j++)
                add_edge(B[i], B[i] - j*P[i], j); //向后跳
        } //这里最大可能加N*sqrt(N)条边 
    } SPFA(); //优化后边数有 N*sqrt(N)的规模
    return 0;
}

Guess you like

Origin www.cnblogs.com/zxytxdy/p/11619858.html