P1955 [NOI2015] 程序自动分析

1|0P1955 [NOI2015] 程序自动分析

1|1基本思路

考虑到了不等号的不可传递性,所以决定只开相等的并查集。

然后突发奇想,觉得可以在找父亲的过程中判断是不是冲突。

然而这样就不能路径压缩,显然超时。

并且,根本没看清楚数据范围,实际上这题的数很大,裸开数组会爆炸。

这是一开始的代码

#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> const int N = 1e8 + 10; int t, n; int x, y, z; int fa[N]; int findSet(int x) { if (x == fa[x]) return x; return findSet(fa[x]); } bool check(int x, int y) { if (y == fa[x]) return false; if (x == fa[x]) return true; return check(fa[x], y); } void merge(int x, int y) { int fx = findSet(x), fy = findSet(y); if (fx == fy) return; fa[fx] = fy; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); std::cin >> t; while(t--) { bool ok = true; memset(fa, 0, sizeof(fa)); std::cin >> n; while(n--) { std::cin >> x >> y >> z; if (z == 1) { if (!fa[x]) fa[x] = x; if (!fa[y]) fa[y] = y; merge(x, y); } else if (ok) ok = (check(x, y) && check(y, x)); } if (ok) std::cout << "YES\n"; else std::cout << "NO\n"; } return 0; }

1|2改进思路

1|0针对超时

其实完全可以继续路径压缩,然后对于一个需要 xy 的情况,直接在相等数构成的并查集里面找二者的父亲,只要相等,就说明冲突。

1|0针对数据

离散化就行

  • 先做好基本的排序、去重。

    这里用std::unique,把重复元素都移到vector尾部。然后dt.erase(std::unique(dt.begin(), dt.end()), dt.end());来去重。

  • 然后进行离散化。

    • 本题可以离散化是因为只要区分出不同数据即可,不需要知道数据本身是什么。

    • 即按照数据在数组中第几大来给数据一个新的映射值。

    • void getLs() { x = lower_bound(dt.begin(), dt.end(), x) - dt.begin(); y = lower_bound(dt.begin(), dt.end(), y) - dt.begin(); fa[x] = x, fa[y] = y; }

1|0代码实现

第一次尝试面向对象风格

#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<vector> const int N = 1e6 + 10; int t, n; int fa[N]; std::vector <int> dt; class Node{ private: int findSet(int x) { return x == fa[x] ? x : fa[x] = findSet(fa[x]); } public: int x, y, z; void read() { std::cin >> x >> y >> z; } bool operator < (const Node& rhs) const { return z > rhs.z; } void getLs() { x = lower_bound(dt.begin(), dt.end(), x) - dt.begin(); y = lower_bound(dt.begin(), dt.end(), y) - dt.begin(); fa[x] = x, fa[y] = y; } void merge() { int fx = findSet(x), fy = findSet(y); if (fx == fy) return; fa[fx] = fy; } bool check() { return findSet(x) == findSet(y); } void outPut() { std::cout << x <<" "<< y << " " << z <<std::endl; } }a[N]; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); std::cin >> t; while(t--) { memset(fa, 0, sizeof(fa)); bool ok = true; std::cin >> n; for (int i = 1; i <= n; i++) { a[i].read(); dt.push_back(a[i].x), dt.push_back(a[i].y); } std::sort(a + 1, a + n + 1); std::sort(dt.begin(), dt.end()); dt.erase(std::unique(dt.begin(), dt.end()), dt.end()); for (int i = 1; i <= n; i++) a[i].getLs(); for (int i = 1; i <= n; i++) { if (a[i].z) a[i].merge(); else if (a[i].check()) { ok = false; std::cout << "NO\n"; break; } } if (ok) std::cout << "YES\n"; } return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17862770.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示