bzoj4078
二分+2-sat
枚举第一个权值,二分第二个权值,然后2-sat检查,当第一个权值已经不能形成二分图时,再往下没意义,因为没法分成两个点集。(双指针好像跑得慢)
#include<bits/stdc++.h> using namespace std; const int N = 410; struct edge { int u, v, w; edge(int u = 0, int v = 0, int w = 0) : u(u), v(v), w(w) {} bool friend operator < (edge A, edge B) { return A.w > B.w; } } e[N * N]; int n, tot, cnt, all, top, ans; int dfn[N], low[N], st[N], belong[N], vis[N], Map[N][N], color[N], fa[N], d[N]; vector<int> G[N], g[N]; int find(int x) { if(fa[x] == x) return x; int ret = find(fa[x]); d[x] ^= d[fa[x]]; return fa[x] = ret; } void tarjan(int u) { dfn[u] = low[u] = ++cnt; st[++top] = u; vis[u] = 1; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], low[v]); } if(low[u] == dfn[u]) { ++all; int j; while(1) { j = st[top]; belong[j] = all; vis[j] = 0; --top; if(j == u) break; } } } bool check(int x, int y) { memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(vis, 0, sizeof(vis)); top = 0; cnt = 0; all = 0; if(x > y) swap(x, y); for(int i = 1; i <= 2 * n; ++i) G[i].clear(); for(int i = 1; i <= tot; ++i) { if(e[i].w > y) { G[e[i].u].push_back(e[i].v + n); G[e[i].v].push_back(e[i].u + n); G[e[i].u + n].push_back(e[i].v); G[e[i].v + n].push_back(e[i].u); } else if(e[i].w > x) { G[e[i].u].push_back(e[i].v + n); G[e[i].v].push_back(e[i].u + n); } } for(int i = 1; i <= 2 * n; ++i) if(!dfn[i]) tarjan(i); for(int i = 1; i <= n; ++i) if(belong[i] == belong[i + n]) return false; return true; } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) fa[i] = i; for(int i = 1; i < n; ++i) for(int j = 1; j <= n - i; ++j) { scanf("%d", &Map[i][i + j]); e[++tot] = edge(i, i + j, Map[i][i + j]); } if(n == 1) { puts("0"); return 0; } ++tot; sort(e + 1, e + tot + 1); ans = 2000000010; int j = tot; for(int i = 1; i <= tot && i <= j; ++i) { while(j && !check(e[i].w, e[j].w)) --j; int u = find(e[i].u), v = find(e[i].v); if(u != v) { ans = min(ans, e[i].w + e[j].w); d[u] = d[e[i].u] ^ d[e[i].v] ^ 1; fa[u] = v; } else if(d[e[i].u] == d[e[i].v]) { ans = min(ans, e[i].w + e[j].w); break; } } printf("%d\n", ans); return 0; }