因爲不夠方便, 因此將 \(T1\) 到 \(T4\) 的題面放到其餘裏面了, 請諒解!
還有模擬賽的連接 傳送門html
咱們能夠這麼想, 既然要求 \(A_m + A_n + A_p = A_i\), 那麼根據 \(n^3\) 的算法來算 \(5000\) 的 \(n\) 是絕對會超時的, 因此咱們考慮用小學的知識 : 移項
可得 \(A_m + A_n = A_i - A_p\)
這樣就能夠二維處理 \(A_m + A_n\) 再存進 \(hash\) 表裏面, 再用 \(A_i - A_p\) 去匹配。 若是匹配成功了, 那麼就存在 \(A_m + A_n + A_p = A_i\), \(ans\) 就 \(++\) 了c++
#include <bits/stdc++.h> #define N 5005 #define M 25000004 #define hu 689207157 #pragma GCC optimize(2) using namespace std; int n, ans, flag; int a[N], hash[M]; int hhd (int x) { int te = (x % M + M) % M; int i = 0; while (i < M && hash[(te + i) % M] != x && hash[(te + i) % M] != hu) i ++; return (te + i) % M; } void insert_hhd (int x) { int dw = hhd (x); hash[dw] = x; } int main () { freopen ("good.in", "r", stdin); freopen ("good.out", "w", stdout); scanf ("%d", &n); for (int i = 0; i < M; ++ i) hash[i] = hu; for (int i = 1; i <= n; ++ i) { flag = 0; scanf ("%d", &a[i]); for (int j = 1; j < i; ++ j) { if (hash[hhd(a[i] - a[j])] == a[i] - a[j] && !flag) { ans ++; flag = 1; break; } } for (int j = 1; j <= i; ++ j) insert_hhd (a[i] + a[j]); } printf ("%d", ans); return 0; }
能夠理解爲一排排好序的數組, 每一個點都有x, y座標。
因此咱們能夠用經典的歐氏距離來求出兩個點之間的距離。算法
而後注意題目要求走徹底部點數組
每一個點通過一次閉包
而後能夠把來去理解爲從 \(A\) 點出發, 走兩個不相交的路徑到達點 \(B\), 因而這道題又能夠轉化爲
兩條不相交路徑最短問題
而後就是 \(DP\), 設狀態 \(f[i][j]\) 爲從點 \(A\) (編號\(1\)) 的兩條路徑分別走到 編號爲 \(i\) 和 編號爲 \(j\) 的兩個點, 再注意判斷一些特殊的點便可。
注意, 要杜絕 \(i == j\) 的狀況 (當 \(i == j == n\)的狀況除外, 由於這樣是走到終點了)。
還有要繼續往前就用一個 \(Max(i, j) + 1\) 便可, 即當前所走的最大編號的點再往前走一步spa
#include <bits/stdc++.h> #define db double #define N 1005 using namespace std; int n, b1, b2; db hhd[N][3], f[N][N]; db dis (int hu, int he) // 傳統的歐氏距離 { db x = (db)(hhd[hu][1] - hhd[he][1]) * (hhd[hu][1] - hhd[he][1]); db y = (db)(hhd[hu][2] - hhd[he][2]) * (hhd[hu][2] - hhd[he][2]); return (db)sqrt (x + y); } void run () { int i, j; for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) f[i][j] = 123456789; f[1][1] = 0; for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) { if (i != j || i == 1) { int k = max (i, j) + 1; if (k == n + 1) { if (j == n) f[n][n] = min (f[n][n], f[i][n] + dis (i, n)); if (i == n) f[n][n] = min (f[n][n], f[n][j] + dis (j, n)); } else { if (k != b1) f[i][k] = min (f[i][k], f[i][j] + dis(j, k)); //回的時候不走b1 if (k != b2) f[k][j] = min (f[k][j], f[i][j] + dis(i, k)); } } } printf ("%.2lf", f[n][n]); } int main () { freopen ("path.in", "r", stdin); freopen ("path.out", "w", stdout); scanf ("%d%d%d", &n, &b1, &b2); b1 += 1, b2 += 1; // 編號是從0開始的 for (int i = 1; i <= n; ++ i) scanf ("%lf%lf", &hhd[i][1], &hhd[i][2]); run (); return 0; }
雖然沒有調出來, 可是思路我仍是很清晰的~.net
有一個前提的基礎, 以下圖
而後就不會了
看看機房dalao的博客傳送門code
第一個思路, 暴力;
能夠跑 \(Dijstkra\) 來肯定哪些點是否相通, 而後再暴力枚舉, 判斷最多能有多少個不相通且兩兩間不相鄰的點。htm
正解 : 傳遞閉包。
其實就是一個二分圖的模板加上 \(floyd\) 就能過了(數據水?)blog
#include <bits/stdc++.h> #define N 205 using namespace std; int n, m, ans; int G[N][N], vis[N], link[N]; int found (int x) { for (int i = 1; i <= n; ++ i) if (!vis[i] && G[x][i]) { vis[i] = 1; if (!link[i] || found (link[i])) { link[i] = x; return 1; } } return 0; } int main () { scanf ("%d%d", &n, &m); for (int i =1; i <= m; ++ i) { int x, y; scanf ("%d%d", &x, &y); G[x][y] = 1; } for (int k = 1;k <= n; ++ k) for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) if (G[i][k] && G[k][j]) G[i][j] = 1; for (int i = 1; i <= n; ++ i) { memset (vis, 0, sizeof (vis)); ans += found (i); } printf ("%d", n - ans); return 0; }