洛谷 P2661 信息传递(tarjan NOIP)

本文介绍了一个信息传递游戏的算法分析,通过Tarjan算法求解游戏的最短轮数。使用了深度优先搜索来查找环,并详细展示了代码实现。

题目链接:https://www.luogu.org/problemnew/show/P2661 

Description

有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
  游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里 获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?

 

Under two situations the player could score one point.

⋅1.If you touch a buoy before your opponent, you will get one point.For example if your opponent touch the buoy #2 before you after start, he will score one point. So when you touch the buoy #2, you won't get any point. Meanwhile, you cannot touch buoy #3 or any other buoys before touching the buoy #2.

⋅2.Ignoring the buoys and relying on dogfighting to get point. If you and your opponent meet in the same position, you can try to fight with your opponent to score one point. For the proposal of game balance, two players are not allowed to fight before buoy #2 is touched by anybody.

There are three types of players.

Speeder: As a player specializing in high speed movement, he/she tries to avoid dogfighting while attempting to gain points by touching buoys.
Fighter: As a player specializing in dogfighting, he/she always tries to fight with the opponent to score points. Since a fighter is slower than a speeder, it's difficult for him/her to score points by touching buoys when the opponent is a speeder.
All-Rounder: A balanced player between Fighter and Speeder.

There will be a training match between Asuka (All-Rounder) and Shion (Speeder).
Since the match is only a training match, the rules are simplified: the game will end after the buoy#is touched by anybody. Shion is a speed lover, and his strategy is very simple: touch buoy #2,#3,#4,#1 along the shortest path.

Asuka is good at dogfighting, so she will always score one point by dogfighting with Shion, and the opponent will be stunned for T seconds after dogfighting.Since Asuka is slower than Shion, she decides to fight with Shion for only one time during the match. It is also assumed that if Asuka and Shion touch the buoy in the same time, the point will be given to Asuka and Asuka could also fight with Shion at the buoy. We assume that in such scenario, the dogfighting must happen after the buoy is touched by Asuka or Shion.

The speed of Asuka is V1 m/s. The speed of Shion is V2 m/s. Is there any possibility for Asuka to win the match (to have higher score)?

Input

输入共2行。
第1行包含1个正整数n表示n个人。
第2行包含n个用空格隔开的正整数T1,T2,……,Tn其中第i个整数Ti示编号为i
的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i
数据保证游戏一定会结束。

Output

输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。

 

Sample Input

5
2 4 2 3 1
 

Sample Output

3

题解:tarjan模板题,直接判环即可。

AC代码:

/*
* @Author: 王文宇
* @Date:   2018-06-15 02:09:37
* @Last Modified by:   王文宇
* @Last Modified time: 2018-06-15 02:14:48
*/
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int maxn = 200006;
stack<int> S;
int n,tot,vis[maxn],ans,low[maxn],dfn[maxn];
vector<int> E[maxn];
void tarjan(int x)
{
	S.push(x);
	vis[x]=1;
	low[x]=dfn[x]=++tot;
	int l = E[x].size()-1;
	_for(i,0,l)
	{
		int now = E[x][i];
		if(dfn[now]==0)
		{
			tarjan(now);
			low[x]=min(low[x],low[now]);
		}
		else if(vis[now])
		{
			low[x]=min(low[x],dfn[now]);
		}
	}
	if(dfn[x]==low[x])
	{
		int t = 0;
		while(1)
		{
			int now = S.top();
			S.pop();
			t++;
			if(x==now)break;
		}
		if(t>1)ans=min(ans,t); 
	}
}
int main(int argc, char const *argv[])
{
	cin>>n;
	_for(i,1,n)
	{
		int x;
		cin>>x;
		E[i].push_back(x);
	}
	ans = maxn;
	_for(i,1,n)
	{
		if(dfn[i]==0)tarjan(i);
	}
	cout<<ans<<endl;
	return 0;
}

### 关于洛谷信息传递问题的分析 #### 题目背景与目标 洛谷 P2661 信息传递是一个典型的图论问题,涉及强连通分量的概念。该题目要求模拟一个信息传播的过程,并找出游戏能够持续的最大轮数[^3]。 #### 解决方法概述 此问题可以通过构建有向图来表示信息传递关系,其中节点代表学生,边 \(i \to T_i\) 表示从学生 \(i\) 向其传递对象 \(T_i\) 的单向连接。最终的目标是找到环路中最短的那个环长度,因为一旦某个学生的生日信息回到他自己手中,则整个游戏结束。 ##### 使用 Tarjan 算法寻找最小环 Tarjan 是一种用于发现无向图或者有向图中所有强联通子图的有效算法,在这里可以用来检测并统计各个独立循环路径大小: ```python def tarjan_scc(graph, N): index_counter = [0] stack = [] on_stack = [False] * (N + 1) indices = [-1] * (N + 1) low_links = [-1] * (N + 1) sccs = [] def strong_connect(v): indices[v] = index_counter[0] low_links[v] = index_counter[0] index_counter[0] += 1 stack.append(v) on_stack[v] = True for w in graph.get(v, []): if indices[w] == -1: strong_connect(w) low_links[v] = min(low_links[v], low_links[w]) elif on_stack[w]: low_links[v] = min(low_links[v], indices[w]) if low_links[v] == indices[v]: scc = [] while True: w = stack.pop() on_stack[w] = False scc.append(w) if w == v: break sccs.append(scc[:]) for node in range(1, N + 1): if indices[node] == -1: strong_connect(node) return sccs ``` 上述代码实现了基于 DFS 的 Tarjan 强连通分量查找函数 `tarjan_scc` ,它接收邻接表形式的输入图以及顶点总数作为参数。 #### 输出结果解释 调用上面定义的方法后得到的结果列表`sccs`包含了所有的强连通分支集合。对于本题而言,我们需要进一步处理这些数据以提取最小子圈尺寸: ```python from collections import defaultdict if __name__ == "__main__": n = int(input()) # 构建图形 edges = list(map(int, input().split())) graph = defaultdict(list) for idx, val in enumerate(edges, start=1): graph[idx].append(val) components = tarjan_scc(dict(graph), n) lengths = sorted([len(c) for c in components]) print(lengths[-1] if lengths else 0) ``` 这段脚本首先读取标准输入中的整数值n和数组edges;接着创建了一个字典类型的graph变量存储各条边的关系;最后运用之前编写的辅助功能完成拓扑排序,并打印出最长周期长度。 #### 总结 综上所述,利用深度优先搜索配合特定的数据结构(如栈),再辅以适当的剪枝策略,就可以高效求解此类复杂度较高的组合优化难题了。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值