鱼C论坛

 找回密码
 立即注册
查看: 2219|回复: 11

[心之碎片][0623] - P3065 [USACO12DEC] First! G

[复制链接]
发表于 2024-6-23 15:21:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
P3065
5 遍过
3 h


知识点
trie, 找环


思路
把所有 str 放进字典树, 如果有前缀就一定不是, 如果有公共前缀就不管它
对于每个分支, 用优先级连边 eg.  a > b : a --> b
判断: 如果这个图里面有环就自己矛盾, 不可能排在第一个


需要进步的地方
思路中的找环没想出来, 还是需要更普遍的东西, 而不是赋值这种可能会出错的
dfs 找环的流程, 分三个状态 : 0 未访问, 1 访问中, 2 访问后
dfs 中如果去到的节点也是 1 , 就有环

代码
  1. #include <bitsdc++.h>
  2. using namespace std;

  3. const int N = 3e5 + 5;

  4. struct Node{
  5.     char ch;
  6.     int ed;
  7.     vector<int> child;
  8. } t[N];

  9. int tot, n;
  10. vector<string> s;

  11. int Newnode(char c){
  12.     tot++;
  13.     t[tot].ch = c;
  14.     return tot;
  15. }

  16. void Insert(int id){
  17.     int u = 0, temp;
  18.     bool f = 0;

  19.     for(auto i : s[id]){
  20.         f = 0;
  21.         for(auto ed : t[u].child){
  22.             if(t[ed].ch == i){
  23.                 f = 1;
  24.                 u = ed;
  25.                 break;
  26.             }
  27.         }
  28.         if(!f){
  29.             temp = Newnode(i);
  30.             t[u].child.emplace_back(temp);
  31.             u = temp;
  32.         }   
  33.     }
  34.     t[u].ed = 1;
  35. }

  36. bitset<30005> vis;
  37. vector<int> e[30];
  38. int v[30];

  39. bool dfs(int u){
  40.     v[u] = 1;
  41.     for(auto ed : e[u]){
  42.         if(v[ed] == 1) return 1;
  43.         if(!v[ed] && dfs(ed)) return 1;
  44.     }
  45.     v[u] = -1;
  46.     return 0;
  47. }

  48. void Query(int id){
  49.     int u = 0, nxt, lst = 0;

  50.     for(int i = 0; i < 26; i++){
  51.         e[i].clear();
  52.         v[i] = 0;
  53.     }

  54.     for(auto i : s[id]){
  55.         if(t[u].ed)
  56.             return ;
  57.         for(auto ed : t[u].child){
  58.             if(t[ed].ch == i){
  59.                 nxt = ed;
  60.                 continue;
  61.             }
  62.             e[i - 'a'].emplace_back(t[ed].ch - 'a');
  63.         }
  64.         u = nxt;
  65.     }

  66.     for(int i = 0; i < 26; i++){
  67.         if(v[i]) continue;
  68.         if(dfs(i)) return ;
  69.     }
  70.     vis[id] = 1;
  71. }

  72. int main(){
  73.     ios::sync_with_stdio(0);
  74.     cin.tie(0);

  75.     cin >> n;
  76.     string str;
  77.     for(int i = 0; i < n; i++){
  78.         cin >> str;
  79.         s.emplace_back(str);
  80.         Insert(i);
  81.     }

  82.     int ans = 0;
  83.     for(int i = 0; i < n; i++){
  84.         Query(i);
  85.         if(vis[i]) ans++;
  86.     }

  87.     cout << ans << '\n';
  88.     for(int i = 0; i < n; i++){
  89.         if(vis[i]) cout << s[i] << '\n';
  90.     }

  91.     return 0;
  92. }
复制代码




本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-6-23 15:21:21 | 显示全部楼层
哈哈,看得出这个问题有点挑战性,不过不用担心,我来帮你以轻松幽默的方式理解这个P3065题目和它背后的算法吧!

### 问题解析:P3065

首先,我们需要理解这个问题想让我们解决什么。简单来说,它涉及到构建一个字典树(Trie)并判断在这个结构里是否有环存在。以下是问题的具体步骤:

1. **构建一个字典树(Trie)**:将所有的字符串插入字典树中。
2. **检测环(Cycle Detection)**:确定是否存在任何环。如果有环,表明存在自相矛盾的情况。

### 具体思路

1. **插入字典树**:
   - 对于每个新插入的字符串,检查其前缀是否已经存在于字典树中,如果有,不需要再插入新的节点。
   
2. **优先级连边**:
   - 根据字母顺序建立图的边,例如,对于 `a > b`,你可以创建 `a -> b` 的边。

3. **检测环**:
   - 使用深度优先搜索(DFS)来检测是否存在环。可以设置三个状态:0(未访问),1(访问中),2(已访问)。

如果在DFS过程中访问到一个正在访问中的节点(状态为1),那么就说明存在环。

### 代码讲解

来,咱们把代码逐步拆解并解释——通过幽默的方式让你记住:

  1. #include <iostream>
  2. #include <vector>
  3. #include <bitset>
  4. using namespace std;

  5. const int N = 3e5 + 5;

  6. struct Node{
  7.     char ch;
  8.     int ed;
  9.     vector<int> child;
  10. } t[N];

  11. int tot, n;
  12. vector<string> s;

  13. int Newnode(char c){
  14.     // 每调这个函数,tot都会增加,表示新增了一个节点
  15.     tot++;
  16.     t[tot].ch = c;
  17.     return tot;
  18. }

  19. void Insert(int id){
  20.     int u = 0, temp;
  21.     bool f = 0;

  22.     for(auto i : s[id]){
  23.         f = 0;
  24.         for(auto ed : t[u].child){
  25.             if(t[ed].ch == i){
  26.                 f = 1;
  27.                 u = ed;
  28.                 break;
  29.             }
  30.         }
  31.         if(!f){
  32.             temp = Newnode(i);
  33.             t[u].child.emplace_back(temp);
  34.             u = temp;
  35.         }   
  36.     }
  37.     t[u].ed = 1;
  38. }

  39. bitset<30> vis;
  40. vector<int> e[26];
  41. int v[26];
  42. bool f;

  43. bool dfs(int u){
  44.     v[u] = 1; // 标记正在访问
  45.     for(auto ed : e[u]){
  46.         if(v[ed] == 1) return true; // 发现环
  47.         if(!v[ed] && dfs(ed)) return true;
  48.     }
  49.     v[u] = 2; // 访问结束
  50.     return false;
  51. }

  52. bool Query(int id){
  53.     int u = 0, nxt, lst = 0;

  54.     for(int i = 0; i < 26; i++){
  55.         e[i].clear();
  56.         v[i] = 0;
  57.     }

  58.     for(auto i : s[id]){
  59.         // 如果碰到了结尾,而且不是自己一定有矛盾
  60.         if(t[u].ed){
  61.             return true;
  62.         }
  63.         for(auto ed : t[u].child){
  64.             if(t[ed].ch == i){
  65.                 nxt = ed;
  66.                 continue;
  67.             }
  68.             e[t[ed].ch - 'a'].emplace_back(t[u].ch - 'a');
  69.         }
  70.         u = nxt;
  71.     }

  72.     for(int i = 0; i < 26; i++){
  73.         if(v[i]) continue;
  74.         if(dfs(i)) return true;
  75.     }
  76.     return false;
  77. }

  78. int main(){
  79.     ios::sync_with_stdio(0);
  80.     cin.tie(0);

  81.     cin >> n;
  82.     s.resize(n);
  83.     for(int i = 0; i < n; i++){
  84.         cin >> s[i];
  85.         Insert(i);
  86.     }

  87.     int ans = 0;
  88.     for(int i = 0; i < n; i++){
  89.         if(Query(i)) ans++;
  90.     }

  91.     cout << ans << endl;
  92.     return 0;
  93. }
复制代码


### 总结

通过构建字典树和使用DFS来检测环,是这个问题的核心操作。你可以想象一下,把所有的字符串像大象那样塞进字典树,然后拿起你的探险帽,进入图中寻找有没有循环的小路。

希望这些解释能让你乐在其中,轻松理解!如果还有其他问题或需要进一步解释的地方,请随时提问哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:31:52 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:32:41 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:32:54 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:33:09 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:33:21 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:33:33 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:33:45 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:33:57 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2024-6-26 20:34:08 | 显示全部楼层

回帖奖励 +1 鱼币

提示: 作者被禁止或删除 内容自动屏蔽
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-6-27 14:52:07 | 显示全部楼层

回帖奖励 +1 鱼币

有又学到了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-27 17:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表