# NOIP2018_旅行
阿新 • • 發佈:2020-08-04
解:
觀察資料範圍,圖的形態為樹或基環樹
當為樹時,顯然,從1號點類似於貪心dfs一遍即可
當為基環樹時,一定有一邊不會被經過,所以標記所有環上的邊
再列舉刪哪一條邊,然後按樹一樣dfs即可
程式碼:
《滿目瘡痍的程式碼》
基環樹怎麼標環啊?改的tarjan
對於原題來說,還需要各種優化卡常
發現普通卡常效果不大,程式98%以上的時間都在刪邊,再跑dfs
所以要用空間換時間,5000*5000的陣列還是開的起的
新增各種記憶化,如果計算過了就不再重複計算,並用陣列取代各種stl
結果:在不開O2情況下,最高600+ms,空間70+mb
#include <bits/stdc++.h> using namespace std; const int N = 5010; // typedef unsigned long long ull; //##################### // ull sol_st, sol_ed; //##################### int n, m; // ull get_clock(){ // ull ret; // __asm__ __volatile__ ("rdtsc\n\t":"=A"(ret):); // return ret; // } inline int read() { int re = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) re = re * 10 + ch - 48, ch = getchar(); return re * f; } int head[N], ver[N << 1], nxt[N << 1], tot; bool del[N]; struct EDGE{ int u, v; }e[N << 1]; void add(int u, int v) { ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot; } int ans[N], res[N], resnum; bool vis[N]; namespace SOLVE_1{ void dfs(int now) { ans[++resnum] = now; vis[now] = true; for (int i = head[now]; i; i = nxt[i]) { int y = ver[i]; if (vis[y]) continue; dfs(y); } } void main() { dfs(1); } } namespace SOLVE_2{ // map<pair<int, int>, bool> bridge; // map<pair<int, int>, bool> del; bool bridge[N][N]; bool del[N][N]; bool calc[N][N]; int dfn[N], low[N]; int num; void tarj(int now, int fa) { dfn[now] = low[now] = ++num; for (int i = head[now]; i; i = nxt[i]) { int y = ver[i]; // if (y == fa) continue; if (!dfn[y]) { tarj(y, now); low[now] = min(low[now], low[y]); if (low[y] > dfn[now]) // bridge[make_pair(now, y)] = true, // bridge[make_pair(y, now)] = true; bridge[now][y] = bridge[y][now] = true; } else if (y ^ fa) low[now] = min(low[now], dfn[y]); } } void dfs(int now) { vis[now] = true; res[++resnum] = now; for (int i = head[now]; i; i = nxt[i]) { int y = ver[i]; // if (vis[y] || del[make_pair(now, y)]) continue; if (vis[y] || del[now][y]) continue; dfs(y); } } inline bool update() { for (int i = 1; i <= n; i++) if (ans[i] ^ res[i]) return ans[i] > res[i]; return false; } void main() { memset(ans, 0x3f, sizeof ans); tarj(1, 0); // sol_st = get_clock(); for (int i = 1; i <= n; i++) for (int j = head[i]; j; j = nxt[j]) { int y = ver[j]; // if (bridge[make_pair(i, y)]) continue; if (bridge[i][y]) continue; if (calc[i][y]) continue; memset(vis, 0, sizeof vis); resnum = 0; // del[make_pair(i, y)] = true; // del[make_pair(y, i)] = true; del[y][i] = del[i][y] = true; calc[y][i] = calc[i][y] = true; dfs(1); // del[make_pair(i, y)] = false; // del[make_pair(y, i)] = false; del[y][i] = del[i][y] = false; if (update()) memcpy(ans, res, sizeof res); } // for (int i = 1; i <= n; i++) // for (int j = head[i]; j; j = nxt[j]) { // int y = ver[j]; // if (bridge[make_pair(i, y)] == false) // cout << "###ring on : " << i << " " << y << endl; // } // sol_ed = get_clock(); } } int main() { // freopen("P5022_23.in", "r", stdin); // freopen("P5022_23.ans", "w", stdout); // ull main_st = get_clock(); n = read(); m = read(); for (int i = 1; i <= m; i++) { int u, v; u = read(); v = read(); add(u, v); add(v, u); e[i].u = u; e[i].v = v; } int tmp[N]; for (int i = 1; i <= n; i++) { memset(tmp, 0, sizeof tmp); for (int j = head[i]; j; j = nxt[j]) tmp[++tmp[0]] = ver[j]; sort(tmp + 1, tmp + 1 + tmp[0]); for (int j = head[i], k = 1; j; j = nxt[j], k++) ver[j] = tmp[k]; } if (m == n - 1) SOLVE_1::main(); else SOLVE_2::main(); // for (int i = 1; i <= n; i++) { // cout << "#### " << i << endl; // for (int j = head[i]; j; j = nxt[j]) // cout << ver[j] << " "; // cout << endl; // } for (int i = 1; i <= n; i++) printf("%d ", ans[i]); puts(""); // ull main_ed = get_clock(); // printf("%.7lf", (sol_ed - sol_st) / ((double)main_ed - main_st)); }