dfs模拟(什么都好,就是超时)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
const int N = 200005, M = 2 * N;
int p[N];
int h[N], e[M], ne[M], idx;
int n,root;
int st[N];
vector<vector<int>> ans;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool dfs(int u, vector<int>& path)
{
if (!st[u])
path.push_back(u);
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (st[j] != 2)
if (dfs(j, path))
return true;
}
st[u] = 2;
if (path.size())return true;
else return false;
}
int main()
{
int _; cin >> _;
while (_--)
{
cin >> n;
ans.clear();
for (int i = 1; i <= n; i++)h[i] = -1;
for (int i = 1; i <= n; i++)st[i] = 0;
idx = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &p[i]);
if (p[i] == i)
root = i;
else add(p[i], i);
}
int cnt = 0;
while (true)
{
vector<int> path;
dfs(root, path);
cnt += path.size();
ans.push_back(path);
if (cnt == n)break;
}
printf("%d\n", ans.size());
for (auto i : ans)
{
printf("%d\n", i.size());
for (auto j : i)
printf("%d ", j);
puts("");
}
}
return 0;
}
几经思考(偷看题解),其实每一颗树的路径都等于其leaf节点的数量,每一条路径就是从叶子节点出发碰到第一个访问过的父亲节点(或根节点)
#include<iostream>
#include<vector>
using namespace std;
const int N = 200005;
int n;
int p[N];
bool st[N];
vector<int> leaf;
int main()
{
int _;
cin >> _;
while (_--)
{
cin >> n;
leaf.clear();
for (int i = 1; i <= n; i++)st[i] = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &p[i]);
st[p[i]] = true;
}
for (int i = 1; i <= n; i++)
{
if (st[i])continue;
leaf.push_back(i);
}
for (int i = 1; i <= n; i++)st[i] = 0;
if (n == 1) {
printf("1\n1\n1\n");
continue;
}
printf("%d\n", leaf.size());
int t;
for (auto u : leaf)
{
t = u;
vector<int> path;
while (!st[t])
{
st[t] = true;
path.push_back(t);
t = p[t];
}
printf("%d\n", path.size());
for (int i = path.size() - 1; ~i; i--)
printf("%d ", path[i]);
puts("");
}
puts("");
}
return 0;
}