P2661 [NOIP2015 提高组] 信息传递

题目背景

NOIP2015 Day1T2

题目描述

有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 Ti​ 的同学。

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

输入格式

输入共 2 行。

第一行包含 1 个正整数 n,表示 n 个人。

第二行包含 n 个用空格隔开的正整数 1,2,⋯ ,T1​,T2​,⋯,Tn​,其中第 i 个整数Ti​ 表示编号为 i 的同学的信息传递对象是编号为 Ti​ 的同学,Ti​≤n 且 Ti​≠i。

输出格式

共一行一个整数,表示游戏一共可以进行多少轮。

输入输出样例

输入 #1

5
2 4 2 3 1

输出 #1

3

说明/提示

样例 1 解释:

游戏的流程如图所示。当进行完第 3 轮游戏后,4 号玩家会听到 2 号玩家告诉他自己的生日,所以答案为 3。当然,第 3 轮游戏后,2 号玩家、 3 号玩家都能从自己的消息来源得知自己的生日,同样符合游戏结束的条件。

  • 对于 30% 的数据,n≤200;
  • 对于 60% 的数据,n≤2500;
  • 对于 100% 的数据,n≤2×105。
#include <bits/stdc++.h>
using namespace std;
const int N=200010;
int n,fa[N],ans=0x3f3f3f3f;
int get (int x,int&cnt) 
{ 
    cnt++;
    if(fa[x]==x)return x;
    else return get(fa[x],cnt);
}
int main () 
{
    cin>>n;
    for (int i=1;i<=n;i++)fa[i] = i;
    for (int i=1;i<=n;i++) 
	{
        int cnt=0,f;
        scanf("%d",&f);
        if (get(f,cnt)==i)ans=min(ans,cnt);
        else fa[i]=f;
    }
    printf("%d",ans);
    return 0;
}

 

### NOIP 2000 提高 单词接龙 P1019 解题思路 此问题的核心在于通过深度优先搜索 (DFS) 构造最长的“单词接龙”。题目要求找到由给定单词成的最长链条,其中每个后续单词必须以前一个单词的结尾字母作为起始字母。以下是详细的解题方法: #### 数据结构设计 为了高效解决该问题,需定义以下几个数据结构: - **`words[]`**: 存储所有的输入单词。 - **`g[][]`**: 表示任意两个单词之间的重叠关系矩阵。具体来说,`g[i][j]` 表示单词 `i` 和单词 `j` 能够拼接时的最大重叠长度[^1]。 - **`used[]`**: 记录每个单词被使用的次数,因为每个单词最多可使用两次。 #### 初始化过程 初始化阶段主要完成以下两步操作: 1. 输入所有单词并构建重叠关系矩阵 `g[][]`。对于每一对单词 `(i, j)`,计算它们能够拼接时的最大前缀/后缀匹配长度[^2]。 2. 找到以指定首字母开头的所有可能单词集合,这些单词将成为 DFS 的起点。 #### 深度优先搜索 (DFS) DFS 是解决问题的主要工具。其核心逻辑如下: - 参数设置:传递当前构造的字符串以及最后使用的单词索引。 - 更新状态变量:每次进入新的递归层之前,增加对应单词的使用计数,并尝试更新全局最优解 `res`。 - 遍历候选节点:检查剩余未完全利用的单词是否能继续延长链表;如果满足条件则进一步深入探索。 - 回溯处理:当退出某一层递归时,减少相应单词的使用标记以便其他分支可以重复考虑它。 下面是基于上述描述的具体 C++ 实现代码: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 25; int n, start_char, used[MAXN]; string words[MAXN], res_str; vector<string> result_words; int g[MAXN][MAXN]; // Function to compute overlap between two strings s and t. int get_overlap(const string &s, const string &t){ int m = min(s.size(), t.size()); for(int k=m;k>=1;--k){ if(s.substr((int)s.size()-k)==t.substr(0,k)) return k; } return 0; } void init(){ cin >> n; for(int i=0;i<n;++i){ cin >> words[i]; } char c; cin >> c; start_char = c - 'a'; memset(g,-1,sizeof(g)); for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ if(i!=j && !g[i][j]){ g[i][j]=get_overlap(words[i],words[j]); } } } } pair<int,string> best_result={0,""}; void dfs(string dragon,int last_word_idx,int length,vector<string>& current_path){ if(length > best_result.first){ best_result = {length,dragon}; result_words=current_path; } for(int next_word=0;next_word<n;++next_word){ if(used[next_word]<2 && g[last_word_idx][next_word]>0 ){ ++used[next_word]; current_path.push_back(words[next_word].substr(g[last_word_idx][next_word])); dfs(dragon+words[next_word].substr(g[last_word_idx][next_word]),next_word,length+(int)(words[next_word].size()-g[last_word_idx][next_word]),current_path); --used[next_word]; current_path.pop_back(); } } } int main(){ ios::sync_with_stdio(false); cin.tie(NULL); init(); vector<pair<char,int>> candidates; for(int i=0;i<n;++i){ if(words[i][0]-'a'==start_char)candidates.emplace_back(make_pair(words[i][0]-'a',i)); } for(auto &[c,idx]:candidates){ fill_n(used,n,0); vector<string> path{words[idx]}; used[idx]++; dfs(words[idx],idx,(int)words[idx].size(),path); } cout << best_result.second.size()<<"\n"; for(auto& word:result_words){ cout<<word<<" "; } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值