#題目連接 BZOJ4727 #題解 前置芝士php
1.競賽圖存在哈密頓路徑 2.競賽圖存在哈密頓迴路,當且僅當它是強聯通的ios
因此咱們將圖縮點後,拓撲排序後必定是一條鏈,且以前的塊內的點和以後塊內的點的邊必定全都由前面指向後面 而每一個塊都是強聯通的,因此咱們從起點出發,必定能找到一條路徑走完後面全部點spa
咱們只需預處理出每一個強聯通塊內的一條哈密頓迴路,就能夠求出答案了code
如今問題轉化成了求競賽圖的哈密頓迴路 咱們先求出一條哈密頓路徑blog
##哈密頓路徑 從競賽圖中任意一個點出發向外擴展,維護一個鏈表 倘若擴展到點$u$ 1.若是$u$指向鏈頭或鏈尾,直接加入鏈表 2.不然鏈的中間必定存在相鄰兩點,使得$i$指向$u$,$u$指向$i + 1$,這時候把$u$插入之間便可排序
##哈密頓迴路 咱們在哈密頓路徑的基礎上構造哈密頓迴路 首先若是存在如圖狀況,前$4$個點構成迴路 咱們先找到最大的一個這樣的迴路,而後只需處理後面不在圈內的幾個點ci
對於一個點$u$,若是存在一條$u$指向圈內點的邊,那麼$u$能夠插入圈內 不然跳過$u$,將$u$和以後插入圈內的點一塊兒插入圈內 因爲圖是強聯通的,因此最後必定能所有加入get
複雜度$O(n^2)$string
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<queue> #include<cmath> #include<map> #define LL long long int #define REP(i,n) for (register int i = 1; i <= (n); i++) #define cls(s,v) memset(s,v,sizeof(s)) #define mp(a,b) make_pair<int,int>(a,b) #define cp pair<int,int> #define res register using namespace std; const int maxn = 2005,maxm = 100005,INF = 0x3f3f3f3f; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();} while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();} return flag ? out : -out; } int tmp[20],ti; inline void write(int x){ ti = 0; while (x) tmp[++ti] = x % 10,x /= 10; while (ti) putchar('0' + tmp[ti--]); } vector<int> S[maxn]; int n,G[maxn][maxn]; int dfn[maxn],low[maxn],Scc[maxn],st[maxn],top,cnt,scci; int nxt[maxn],head[maxn],tail[maxn]; int Nxt[maxn],Head[maxn],Tail[maxn]; int g[maxn][maxn],de[maxn],q[maxn],hh,tt; int tp[maxn],pos[maxn],ans[maxn],ansi,tot; int c[maxn],ci; void dfs(int u){ dfn[u] = low[u] = ++cnt; st[++top] = u; for (res int to = 1; to <= n; to++){ if (!G[u][to]) continue; if (!dfn[to]){ dfs(to); low[u] = min(low[u],low[to]); } else if (!Scc[to]) low[u] = min(low[u],dfn[to]); } if (low[u] == dfn[u]){ scci++; do{ Scc[st[top]] = scci; S[scci].push_back(st[top]); }while (st[top--] != u); } } void workline(){ int siz; for (res int p = 1; p <= scci; p++){ siz = S[p].size(); head[p] = tail[p] = S[p][0]; for (res int i = 1; i < siz; i++){ int u = S[p][i]; if (G[u][head[p]]) nxt[u] = head[p],head[p] = u; else if (G[tail[p]][u]) nxt[tail[p]] = u,tail[p] = u; else for (res int j = head[p]; j; j = nxt[j]) if (G[j][u] && G[u][nxt[j]]){ nxt[u] = nxt[j]; nxt[j] = u; break; } } } } void workcir(){ int p,last; for (int i = 1; i <= scci; i++){ ci = 0; p = 1; for (int k = head[i]; k; k = nxt[k]) c[++ci] = k; for (int k = ci; k; k--) if (G[c[k]][head[i]]) {p = k; break;} Head[i] = c[1]; Tail[i] = c[p]; for (int k = 1; k < p; k++) Nxt[c[k]] = c[k + 1]; last = c[p + 1]; for (int k = p + 1; k <= ci; k++){ int u = c[k],flag = false; for (int j = Nxt[Head[i]],pre = Head[i]; j; j = Nxt[pre = j]) if (G[u][j]){ Nxt[pre] = last; Nxt[u] = j; flag = true; break; } if (flag) last = c[k + 1]; else Nxt[u] = c[k + 1]; } Nxt[Tail[i]] = Head[i]; } } void work(){ for (res int i = 1; i <= n; i++){ int u = Scc[i]; for (res int j = 1; j <= n; j++) if (G[i][j] && Scc[j] != u && !g[u][Scc[j]]) de[Scc[j]]++,g[u][Scc[j]] = 1; } for (res int i = 1; i <= scci; i++) if (!de[i]) q[++tt] = i; int u; hh = 1; while (hh <= tt){ u = q[hh++]; pos[u] = ++tot; tp[tot] = u; for (int i = 1; i <= scci; i++) if (g[u][i]){ if (!(--de[i])) q[++tt] = i; } } for (res int u = 1; u <= n; u++){ int s = Scc[u]; ans[ansi = 1] = u; for (res int i = Nxt[u]; i != u; i = Nxt[i]) ans[++ansi] = i; for (res int j = pos[s] + 1; j <= scci; j++){ int t = tp[j]; ans[++ansi] = Head[t]; for (res int i = Nxt[Head[t]]; i != Head[t]; i = Nxt[i]) ans[++ansi] = i; } write(ansi); putchar(' '); for (res int i = 1; i <= ansi; i++){ write(ans[i]); if (i < ansi) putchar(' '); } puts(""); } } int main(){ n = read(); for (res int i = 2; i <= n; i++) for (res int j = 1; j < i; j++) G[i][j] = ((G[j][i] = read()) ^ 1); REP(i,n) if (!dfn[i]) dfs(i); workline(); //puts("LXT"); workcir(); //puts("LXT"); work(); return 0; }