思路:
首先,竞赛图在缩点之后会形成一条链,然后在同一个强联通分量内的点都具有哈密顿回路,这道题的做法就很清晰了:先找出每个连通分量的哈密顿回路,然后对于每个点,从其所在的连通分量开始走一直走到链的另外一端,就是最长的路径.
接下来我们将构造哈密顿回路:
首先构造哈密顿通路, 对于任意的竞赛图都存在哈密顿通路.
假设我们构造好了前i - 1个点的哈密顿通路.
上面只标出与通路有关的点和边,S为起点,T为终点.那么第i个点一定至少满足下面三个条件之一:
1.i -> S
2.T-> i
3.x -> i, i -> nxt[x](x ∈[1, i - 1]).
我们可以用画图证明:
容易知道,上面两种情况是不满足第一,二个前提下,对于第三个前提最坏的情况,但是我们仍能找出满足第三个前提的路径(S -> i, i -> nxt[S]和 pre[T] -> i, i -> T).
所以我们构造通路的策略是:
1.先找i -> S,如果有则让S = i.
2.再找T -> i,如果有则让T = i.
3.枚举每个点,找到j -> i, i -> nxt[j],然后把这个点插入路径即可.
if (scc[cc].size() == 1) return;
int s = scc[cc][0], t = s;
for (int i = 1; i < scc[cc].size(); ++i) {
int x = scc[cc][i];
if (g[t][x]) nxt[t] = x, t = x;
else if (g[x][s]) nxt[x] = s, s = x;
else {
for (int j = s; j != t; j = nxt[j])
if (g[j][x] && g[x][nxt[j]]) {
nxt[x] = nxt[j], nxt[j] = x;
break;
}
}
}
接下来就是用已经构造好的哈密顿通路来构造哈密顿回路了.
具体的步骤如下:
1.如果出现i -> S,那么就把i设置新的T.由于是处于强连通分量,所以一定会出现这种情况,所以一定有终点.
2.假设起点是S,终点为T, x是路径上的其中一点,如果存在i -> x, 那么我们按照下图构造路径.
其中紫色路径就是我们要新构造的路径,这里我们假设x的前驱是pre[x],T的后继是nxt[T],从pre[x]到nxt[T]这段路是通过其他点到达的,因为是同一个强联通分量.
我们在S到T这条路径上找出一个点x满足这个条件即可.
t = 0;
for (int i = nxt[s]; i; i = nxt[i])
if (t) {
if (g[i][s]) t = i;
else {
for (int j = s, k = nxt[s]; j != t; j = k, k = nxt[k])
if (g[i][k]) {
nxt[j] = nxt[t], nxt[t] = s, s = k, t = i;
break;
}
}
}else if (g[i][s]) t = i;
nxt[t] = s;
完整代码:
时间复杂度O(n^2)
#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define ll long long
// #define double long double
#define ull unsigned long long
#define PII pair<int, int>
#define PDI pair<double, int>
#define PDD pair<double, double>
#define debug(a) cout << #a << " = " << a << endl
#define point(n) cout << fixed << setprecision(n)
#define all(x) (x).begin(), (x).end()
#define mem(x, y) memset((x), (y), sizeof(x))
#define lbt(x) (x & (-x))
#define SZ(x) ((x).size())
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
namespace nqio{const unsigned R = 4e5, W = 4e5; char *a, *b, i[R], o[W], *c = o, *d = o + W, h[40], *p = h, y; bool s; struct q{void r(char &x){x = a == b && (b = (a = i) + fread(i, 1, R, stdin), a == b) ? -1 : *a++;} void f(){fwrite(o, 1, c - o, stdout); c = o;} ~q(){f();}void w(char x){*c = x;if (++c == d) f();} q &operator >>(char &x){do r(x);while (x <= 32); return *this;} q &operator >>(char *x){do r(*x); while (*x <= 32); while (*x > 32) r(*++x); *x = 0; return *this;} template<typename t> q&operator>>(t &x){for (r(y),s = 0; !isdigit(y); r(y)) s |= y == 45;if (s) for (x = 0; isdigit(y); r(y)) x = x * 10 - (y ^ 48); else for (x = 0; isdigit(y); r(y)) x = x * 10 + (y ^ 48); return *this;} q &operator <<(char x){w(x);return *this;}q &operator<< (char *x){while (*x) w(*x++); return *this;}q &operator <<(const char *x){while (*x) w(*x++); return *this;}template<typename t> q &operator<< (t x) {if (!x) w(48); else if (x < 0) for (w(45); x; x /= 10) *p++ = 48 | -(x % 10); else for (; x; x /= 10) *p++ = 48 | x % 10; while (p != h) w(*--p);return *this;}}qio; }using nqio::qio;
using namespace std;
const int N = 2e3 + 10;
int n, g[N][N];
int dfn[N], low[N], tim, c[N], cnt, instk[N], stk[N], top, in[N], pos[N], nxt[N];
vector<int> son[N], scc[N], sson[N], ans[N];
void tarjan(int x) {
dfn[x] = low[x] = ++tim;
stk[++top] = x; instk[x] = 1;
for (int i = 1, y; i <= n; ++i) {
if (!g[x][y = i]) continue;
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
}else if (instk[y]) low[x] = min(low[x], dfn[y]);
}
if (dfn[x] == low[x]) {
++cnt; int y;
do {
y = stk[top--];
c[y] = cnt; scc[cnt].emplace_back(y);
} while (x != y);
}
}
void solve(int cc) {
if (scc[cc].size() == 1) return;
int s = scc[cc][0], t = s;
for (int i = 1; i < scc[cc].size(); ++i) {
int x = scc[cc][i];
if (g[t][x]) nxt[t] = x, t = x;
else if (g[x][s]) nxt[x] = s, s = x;
else {
for (int j = s; j != t; j = nxt[j])
if (g[j][x] && g[x][nxt[j]]) {
nxt[x] = nxt[j], nxt[j] = x;
break;
}
}
}
t = 0;
for (int i = nxt[s]; i; i = nxt[i])
if (t) {
if (g[i][s]) t = i;
else {
for (int j = s, k = nxt[s]; j != t; j = k, k = nxt[k])
if (g[i][k]) {
nxt[j] = nxt[t], nxt[t] = s, s = k, t = i;
break;
}
}
}else if (g[i][s]) t = i;
nxt[t] = s;
}
signed main() {
qio >> n;
for (int i = 2; i <= n; ++i)
for (int j = 1, x; j <= i - 1; ++j) {
qio >> x;
if (x) son[j].emplace_back(i), g[j][i] = 1;
else son[i].emplace_back(j), g[i][j] = 1;
}
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= cnt; ++i)
for (int j : scc[i])
for (int k = 1; k <= n; ++k)
if (g[j][k] && i != c[k])
sson[i].emplace_back(c[k]), ++in[c[k]];
// for (int i = 1; i <= n; ++i)
// for (int x : son[i])
// if (c[x] != c[i])
// sson[c[i]].emplace_back(c[x]), ++in[c[x]];
queue<int> q;
// top = 0;
for (int i = 1; i <= cnt; ++i) if (!in[i]) q.emplace(i);
while (q.size()) {
int x = q.front(); q.pop();
stk[++top] = x; pos[x] = top;
for (int i : sson[x]) if (--in[i] == 0) q.emplace(i);
}
for (int i = 1; i <= top; ++i) solve(stk[i]);
for (int i = 1; i <= n; ++i) {
int lst = i, now = pos[c[i]];
while (1) {
if (scc[stk[now]].size() == 1) {
ans[i].emplace_back(lst);
if (now == top) break;
lst = scc[stk[++now]][0];
continue;
}
ans[i].emplace_back(lst);
for (int x = nxt[lst]; x != lst; x = nxt[x])
ans[i].emplace_back(x);
if (now == top) break;
lst = scc[stk[++now]][0];
}
}
for (int i = 1; i <= n; ++i) {
qio << ans[i].size() << " ";
for (int x : ans[i]) qio << x << " ";
qio << "\n";
}
}