1 条题解
-
0
自动搬运
来自洛谷,原作者为

KesdiaelKen
**搬运于
2025-08-24 21:40:09,当前版本为作者最后更新于2017-09-23 10:56:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
嗯……本人表示真的还不会toposort……所以,我就打了个奇奇怪怪的方法,居然也过了。
下面介绍一下我在本题的经历——
首先,我以为用set暴力判重能过,然而T了6个点。
然后,我彻夜不眠,思考着本题。然后,我就想出来了,然后就过了……
好吧,还是介绍一下思路。
可以把这些关系看成一个有向图。对于任意一个节点进入,因为每个点的出度均为1,所以最多只能构成三种情况:1、一条链;2、一个环链;3、一条链连接着一个环链。因为这三种情况极为的简单,所以就可以如下处理:
找任意一个点进入,记录到达每一个点所走过的遍数。当走到一个在这次查找中已经出现过的节点,即找到了一个环,用当前走到的步数减去在此节点原先记录的步数,便得到这个环的长度。由此搜遍所有点,找到这些环中最小长度的一个,并把它输出就可以了。
而如果就这样去做,会TLE,所以得再加一点优化。对于一次查找环中,由于此次查找中至多只有一个环,而此环已经确定,所以再有外部的链介入此环,它的状态仍然不变。所以可以加个判断,如果走到了已经被查找过的节点,便直接跳出。
下为代码,供大家参考:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; int dx[300000];//存每一个人传话的对象 bool visit[300000]={0},novisit[300000]={0};//visit存每次查找中被查到的点,而novisit存每次查找前,已经被查找过的点(及不用继续查找了) int bs[300000]={0};//每次查找中第一次到一个节点所经过的边数 int minn=2e9; void dfs(int node,int num) { if(novisit[node])return;//不需要继续找了 if(visit[node])//在此次查找中出现过 { minn=min(minn,num-bs[node]);//形成一个环,取最小值 } else { visit[node]=true;//在此次循环中经过 bs[node]=num;//记录第一次到达时的步数 dfs(dx[node],num+1);//搜索 novisit[node]=true;//已经搜过 } } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&dx[i]); } for(int i=1;i<=n;i++) { dfs(i,0);//枚举全部节点 } printf("%d",minn);//输出 return 0;//时间复杂度O(n) }
- 1
信息
- ID
- 1619
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者