abc233_f Swap and Sort 题解
Swap and Sort
题意
有一个
有
请问最多执行
- 如果可能,第一行输出操作次数,第二行输出操作序列
- 否则,输出
-1
数据范围
且当 时
思路
建图
详见代码注释。
次数限制分析
首先来分析一下:
- 同一个操作执行了偶数次,就相当于没有执行
- 同一个操作执行了奇数次,就相当于执行
次
所以在操作次数尽量小的情况下,最多执行
然后就会惊喜地发现:
图->树
接下来就需要把有环图转成树了。
由于我们分析了次数限制不是很重要,所以是可以断掉环上的任意的边的,因为不需要操作数量最小。
求答案
找答案其实很简单,只要注意细节,为了防止在交换之后原本处理好的节点重新被交换到了一个错误的地方,我们只能去求每棵树的叶子节点。
复杂度
- 时间:
- 空间:
Code
点击查看代码
#include <iostream> #include <vector> #include <queue> using namespace std; const int M = 2e5 + 10; struct node { int x, id; }; int n, m, a[1010], f[1010], l, r, num, b[1010], fa[1010]; vector<node> nv[1010], v[1010]; vector<int> ans; queue<int> q; void stree (int x) { f[x] = 1; // 标记这个节点在图中 for (auto i : nv[x]) { if (!f[i.x]) { v[x].push_back({i.x, i.id}), v[i.x].push_back({x, i.id}), b[x]++, fa[i.x] = x, stree(i.x); // 记录这个节点的儿子 } } } void dfs (int x, int y, int sum) { if (a[x] == l) { // 终于交换到了目的地 num = sum; // 记录答案 return ; } for (auto i : v[x]) { if (i.x != y) { // 不是上一个节点 dfs(i.x, x, sum + 1); // 进行dfs } if (num != -1) { // 已经交换到了目的地 ans.push_back(i.id); swap(a[x], a[i.x]); // 记得真正地交换一下 return ; } } } void Ans () { // 求答案 for (int i = 1; i <= n; i++) { if (!b[i]) { // 是叶子节点 q.push(i); } } while (!q.empty()) { l = q.front(), num = -1, q.pop(); dfs(l, 0, 0); if (num == -1) { // 到不了目标点 cout << -1; exit(0); } b[fa[l]]--; // 当前点没了,它的父亲的儿子数量要减1 if (!b[fa[l]]) { // 它的父亲成了叶子节点 q.push(fa[l]); // 加入答案处理队伍 } } } int main(){ ios::sync_with_stdio(0), cin.tie(0); cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; } cin >> m; for (int i = 1; i <= m; i++) { cin >> l >> r, nv[r].push_back({l, i}), nv[l].push_back({r, i}); // 记录交换 } for (int i = 1; i <= n; i++) { if (!f[i]) { stree(i); // 生成树 } } Ans(); cout << ans.size() << '\n'; for (auto i : ans) { cout << i << ' '; // 处理操作序列 } return 0; }
本文作者:wnsyou の blog
本文链接:https://www.cnblogs.com/wnsyou-blog/p/17176666.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步