Description
Solution
Task 1
考虑将所有点以
y
y
为第一关键字、为第二关键字排序。
y
y
<script type="math/tex" id="MathJax-Element-157">y</script>坐标相同的点放在一起DP。
记录两个前驱。一个是在本行的前驱,如果无需跳到别的点,那么前驱等于自己;另一个是下一行的前驱。DFS一遍就可以把路径找出来了。
Task 2
要求选最少的路径遍历所有的边,直接搞上下界最小流就行了。
Code
很多同学因为这题代码比较长就不想写啊。其实码量还好吧,也就8.4KB左右(逃
/**************************************
* Au: Hany01
* Prob: [BZOJ4200][NOI2015]
* Date: Jul 21st, 2018
* Email: hany01@foxmail.com
**************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = j; i < i##_end_; ++ i)
#define For(i, j ,k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define SZ(a) ((int)(a.size()))
#define ALL(a) a.begin(), a.end()
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define x first
#define y second
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define y1 wozenmezhemecaia
#ifdef hany01
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
register char c_; register int _, __;
for (_ = 0, __ = 1, c_ = getchar(); !isdigit(c_); c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; isdigit(c_); c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 5e4 + 7;
struct Point { int x, y, id; }p[maxn];
bool operator < (Point A, Point B) { return A.y == B.y ? A.x < B.x : A.y < B.y; }
int n;
set<int> G[maxn];
namespace DynamicProgramming
{
map<int, PII> dp1, dp2, dp3;
vector<int> pr[maxn], prl[maxn], now;
PII range[maxn];
int Ans, g[maxn], f[maxn];
inline void DP()
{
//x x+y x-y
dp1[0].x = dp2[0].x = dp3[0].x = 0, Set(g, -1);
For(r, 1, n) {
//Get the range
register int l = r, mx;
while (r < n && p[r + 1].y == p[r].y) ++ r;
//get g
For(i, l, r) {
range[i] = mp(l, r);
register int x = p[i].x, y = p[i].y;
if (dp1.find(x) != dp1.end()) chkmax(g[i], dp1[x].x);
if (dp2.find(x + y) != dp2.end()) chkmax(g[i], dp2[x + y].x);
if (dp3.find(x - y) != dp3.end()) chkmax(g[i], dp3[x - y].x);
if (dp1.find(x) != dp1.end() && g[i] == dp1[x].x) pr[i].pb(dp1[x].y);
if (dp2.find(x + y) != dp2.end() && g[i] == dp2[x + y].x) pr[i].pb(dp2[x + y].y);
if (dp3.find(x - y) != dp3.end() && g[i] == dp3[x - y].x) pr[i].pb(dp3[x - y].y);
f[i] = g[i] + 1;
if (g[i] >= 0) prl[i].pb(i);
}
//get f
mx = -1, now.clear();
For(i, l, r) {
if (mx != -1) {
if (chkmax(f[i], i - l + 1 + mx)) prl[i] = now;
else if (f[i] == i - l + 1 + mx) rep(j, SZ(now)) prl[i].pb(now[j]);
}
if (chkmax(mx, g[i])) now.clear(), now.pb(i);
else if (mx != -1 && mx == g[i]) now.pb(i);
}
mx = -1, now.clear();
Fordown(i, r, l) {
if (mx != -1) {
if (chkmax(f[i], r - i + 1 + mx)) prl[i] = now;
else if (f[i] == r - i + 1 + mx) rep(j, SZ(now)) prl[i].pb(now[j]);
}
if (chkmax(mx, g[i])) now.clear(), now.pb(i);
else if (mx != -1 && mx == g[i]) now.pb(i);
chkmax(Ans, f[i]);
if (f[i]) {
if (chkmax(dp1[p[i].x].x, f[i])) dp1[p[i].x].y = i;
if (chkmax(dp2[p[i].x + p[i].y].x, f[i])) dp2[p[i].x + p[i].y].y = i;
if (chkmax(dp3[p[i].x - p[i].y].x, f[i])) dp3[p[i].x - p[i].y].y = i;
}
}
}
printf("%d\n", Ans);
/*For(i, 1, n) {
printf("%d: ", p[i].id);
rep(j, SZ(prl[i])) cout << p[prl[i][j]].id << ' ';
cout <<"|";
rep(j, SZ(pr[i])) cout << p[pr[i][j]].id << ' ';
cout << endl;
}*/
}
static int nxt[maxn], vis[maxn], fin = 0;
void DFS(int u)
{
//cout << "VISIT: " << u <<endl;
vis[u] = 1;
if (!u && !fin) {
fin = 1;
for ( ; ; ) {
u = nxt[u];
if (!u) break;
printf("%d ", p[u].id);
if (p[nxt[u]].y == p[u].y && u != nxt[u]) {
if (p[nxt[u]].x < p[u].x) {
For(i, u + 1, range[u].y) printf("%d ", p[i].id);
Fordown(i, u - 1, nxt[u] + 1) printf("%d ", p[i].id);
} else {
Fordown(i, u - 1, range[u].x) printf("%d ", p[i].id);
For(i, u + 1, nxt[u] - 1) printf("%d ", p[i].id);
}
}
if (nxt[u] == u) u = nxt[u];
}
putchar('\n');
return;
}
rep(i, SZ(prl[u])) {
rep(j, SZ(pr[prl[u][i]])) {
if (!vis[pr[prl[u][i]][j]]) {
nxt[pr[prl[u][i]][j]] = prl[u][i];
if (u != prl[u][i]) nxt[prl[u][i]] = u;
DFS(pr[prl[u][i]][j]);
}
G[pr[prl[u][i]][j]].insert(prl[u][i]);
}
}
}
inline void FindPath() {
For(i, 1, n) if (f[i] == Ans) DFS(i);
//For(i, 1, n) cout << f[i] << ' ' ; cout << endl;
}
}
namespace NetworkFlow
{
const int maxm = maxn << 3;
int beg[maxn], nex[maxm], v[maxm], f[maxm], e = 1, s, t, S, T, deg[maxn], vis[maxn], lev[maxn], cur[maxn];
//map<int, int> las1, las2, las3;
inline void add(int uu, int vv, int ff, int mk = 1) {
v[++ e] = vv, f[e] = ff, nex[e] = beg[uu], beg[uu] = e;
if (mk) add(vv, uu, 0, 0);
}
inline bool BFS(int S, int T) {
static queue<int> q;
Set(lev, 0), lev[S] = 1, q.push(S);
while (!q.empty()) {
int u = q.front(); q.pop();
for (register int i = beg[u]; i; i = nex[i])
if (f[i] && !lev[v[i]]) lev[v[i]] = lev[u] + 1, q.push(v[i]);
}
return lev[T];
}
int DFS(int u, int T, int flow)
{
if (u == T) return flow;
int res = flow, t;
for (register int& i = cur[u]; i; i = nex[i]) if (f[i] && lev[v[i]] == lev[u] + 1) {
f[i] -= (t = DFS(v[i], T, min(f[i], res))), f[i ^ 1] += t;
if (!(res -= t)) break;
}
return flow - res;
}
inline int MaxFlow(int S, int T) {
register int Flow = 0;
while (BFS(S, T)) Cpy(cur, beg), Set(vis, 0), Flow += DFS(S, T, INF);
return Flow;
}
void Build()
{
//For(i, 0, n) for (set<int>::iterator j = G[i].begin(); j != G[i].end(); ++ j) cout << i << "--->" << (*j) << endl;
/*las1[0] = las2[0] = las3[0] = 0;
For(i, 1, n) {
if (las1.find(p[i].x) != las1.end()) add(las1[p[i].x], i, INF);
if (las2.find(p[i].x + p[i].y) != las2.end()) add(las2[p[i].x + p[i].y], i, INF);
if (las3.find(p[i].x - p[i].y) != las3.end()) add(las3[p[i].x - p[i].y], i, INF);
las1[p[i].x] = i, las2[p[i].x + p[i].y] = i, las3[p[i].x - p[i].y] = i;
}*/
For(i, 0, n) for (set<int>::iterator j = G[i].begin(); j != G[i].end(); ++ j)
++ deg[i], -- deg[*j], add(i, *j, INF);
s = n + 1, t = s + 1, S = t + 1, T = S + 1;
For(i, 0, n) {
add(i, t, INF), add(s, i, INF);
if (deg[i] > 0) add(i, T, deg[i]);
else if (deg[i] < 0) add(S, i, -deg[i]);
}
add(t, s, INF);
}
void Solve()
{
int Ans;
MaxFlow(S, T), Ans = f[e];
f[e] = f[e ^ 1] = 0, Ans -= MaxFlow(t, s);
printf("%d\n", Ans);
}
}
int main()
{
#ifdef hany01
File("bzoj4200");
#endif
n = read();
For(i, 1, n) p[i].x = read(), p[i].y = read(), p[i].id = i;
sort(p + 1, p + 1 + n);
DynamicProgramming:: DP(), DynamicProgramming:: FindPath();
NetworkFlow:: Build(), NetworkFlow:: Solve();
return 0;
}