P5151 HKE与他的小朋友 题解

Posted begin-ac

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5151 HKE与他的小朋友 题解相关的知识,希望对你有一定的参考价值。

传送门:P5151

不难发现小朋友的运动是一种只和座位有关的有方向的运动,因此可以用点来存储座位,用有向边来存储小朋友的运动轨迹。

注意到点数等于边数,因此这张图只能是一个或多个环,才能满足所有人均能多次移动的性质。则问题可以简化为:给定一些环,求在环上运动 k 次后各点的位置。

那么可以很简单的想到判环。在这里直接使用 bfs 判环即可。在判环的同时,还要记录下每个环的大小 Ti? ,用于简化每个小朋友的位移量 xi = k mod Ti。并将每个环断开扔入一个链表里面,辅助后续查询。代码如下。

vector<int> list[MAXN];//存储环的链表,这里直接用vector代替
int land[MAXN][2];
//存储与环有关的数据
//第0维存储环的编号,第1位存储这该元素是环的第几号元素
int nxt[MAXN];//存下一个点的编号
int T[MAXN];//记录环的大小
int S[MAXN];//手写栈
int lis;//记录环的编号

void bfs1(int st)
    int x = st/*遍历环上的每一个节点*/, tops = 0/*栈顶*/,first = 1/*只是个标记*/;
    while (x != st || first)//遍历环
        first = 0;
        T[st]++;//环的大小增加
        list[lis].push_back(x);//把点扔到链表里
        land[x][0] = lis;
        land[x][1] = tops;//记录有关信息
        S[tops++] = x;//入栈
        x = nxt[x];//遍历下一个点
    
    while (tops--)//修改每一个点记录的环大小
        T[ S[tops] ] = T[st];
    //这里也可以不用栈存储,但是手写栈是最简单的。
    lis++;//环的编号增加

判环之后就是处理答案部分,但是要注意的一点是,这道题不是让你输出每个点在 k 次移动后的位置,而是 k 次移动后每个点上是原来的哪个点。很容易写出这样的代码。

int bfs2(int st, int k)
    int step = k % T[st];//计算有用的位移量
    step += land[st][1];//计算相对于环中一号点的位移量
    if (step >= T[st]) step -= T[st];//控制位移量在1 ~ T_i
    return list[ land[st][0] ][step];//返回该点坐标


for (int i = 1; i <= n; i++) ans[bfs2(i, k)] = i;
//枚举每个点,计算其结束坐标

这些工作都做完好,就可以愉快的切掉这道题了。

完整无修代码

#include <iostream>
#include <vector>
#define MAXN 100005
using namespace std;

vector<int> list[MAXN];
int land[MAXN][2];
int nxt[MAXN],T[MAXN],S[MAXN],ans[MAXN];
int lis;

void bfs1(int st)
    int x = st, tops = 0,first = 1;
    while (x != st || first)
        first = 0;
        T[st]++;
        list[lis].push_back(x);
        land[x][0] = lis;
        land[x][1] = tops;
        S[tops++] = x;
        x = nxt[x];
    
    while (tops--)
        T[ S[tops] ] = T[st];
    
    lis++;


int bfs2(int st, int k)
    int step = k % T[st];
    step += land[st][1];
    if (step >= T[st]) step -= T[st];
    return list[ land[st][0] ][step];


int main()
    int n, k;
    cin>>n>>k;
    for (int i = 1; i <= n; i++) cin>>nxt[i];
    for (int i = 1; i <= n; i++) if (!T[i]) bfs1(i);
    for (int i = 1; i <= n; i++) ans[bfs2(i, k)] = i;
    for (int i = 1; i <= n; i++) cout<<ans[i]<<" ";
    return 0;

 

以上是关于P5151 HKE与他的小朋友 题解的主要内容,如果未能解决你的问题,请参考以下文章

我有一个前端男朋友

BZOJ2330 糖果题解 查分约束

HUT 线段树练习 部分题解

COCI 2011-2012 setnja

如何在应用程序中获取用户 Facebook 朋友的姓名、数量和 ID? [关闭]

「SCOI2011」糖果