pair套pair套pair套pair!多么优(S)雅(B)的代码!
题解:
最小环,有且仅有一条边不在最小生成树上。
注意到一个性质:在最小生成树上ADD一条非树边,我们会得到一个环,那么这条非树边肯定是环上权值最大的。
然后就可以反证了。
【UPD2018/10/9:反证个锤子啊,这个做法整个就错了啊。最小环可以有超过一条边不在生成树上的,数据水了啊】
#include <iostream> #include <cstring> #include <vector> #include <map> #include <algorithm> using namespace std; #define mp make_pair const int INF = 1000000007; typedef pair<int, int> pii; const int N = 8002; int t, n, cas; int x[N], y[N], c[N], d[N], w[N], used[N]; map<pii, int> id; int cnt; int par[N]; vector< pair< pair<int, pii>, int> > edge; vector<pii> g[N]; int vis[N]; // Tree int fa[N][20], dep[N], sum[N][20]; int find(int x) { return par[x] = (par[x] == x) ? x : par[x] = find(par[x]); } void dfs(int u, int p) { vis[u] = 1; for (int i = 0; i < g[u].size(); i ++) { int v = g[u][i].first; if (v == p) continue; dep[v] = dep[u] + 1; fa[v][0] = u; sum[v][0] = g[u][i].second; dfs(v, u); } } void init_LCA() { for (int i = 1; i <= cnt; i ++) if (! vis[i]) { dep[i] = 1, fa[i][0] = 1; sum[i][0] = 0; dfs(i, -1); } for (int i = 1; i < 20; i ++) { for (int j = 1; j <= cnt; j ++) { sum[j][i] = sum[j][i-1] + sum[fa[j][i-1]][i-1]; fa[j][i] = fa[fa[j][i-1]][i-1]; } } } int query(int u, int v) { int ret = 0; if (dep[u] < dep[v]) swap(u, v); int dt = dep[u] - dep[v]; for (int i = 0; i < 20; i ++) { if ( (dt >> i) & 1 ) ret += sum[u][i], u = fa[u][i]; } if (u == v) return ret; for (int i = 19; i >= 0; i --) { if (fa[u][i] != fa[v][i]) ret += sum[u][i] + sum[v][i], u = fa[u][i], v = fa[v][i]; } ret += sum[u][0] + sum[v][0]; return ret; } void init() { for (int i = 0; i < N; i ++) { par[i] = i, used[i] = 0, vis[i] = 0; g[i].clear(); } edge.clear(); id.clear(); cnt = 0; scanf("%d", &n); for (int i = 1; i <= n; i ++) { scanf("%d %d %d %d %d", &x[i], &y[i], &c[i], &d[i], &w[i]); if (! id[mp(x[i], y[i])]) id[mp(x[i], y[i])] = ++ cnt; if (! id[mp(c[i], d[i])]) id[mp(c[i], d[i])] = ++ cnt; edge.push_back(mp(mp(w[i], mp(id[mp(x[i], y[i])], id[mp(c[i], d[i])])), i)); } sort(edge.begin(), edge.end()); for (int i = 0; i < edge.size(); i ++) { int u = edge[i].first.second.first; int v = edge[i].first.second.second; int pu = find(u), pv = find(v); if (pu != pv) { used[edge[i].second] = 1; g[u].push_back( make_pair(v, edge[i].first.first) ); g[v].push_back( make_pair(u, edge[i].first.first) ); par[pu] = pv; } } init_LCA(); } void ok() { int ret = INF; for (int i = 1; i <= n; i ++) { if (used[i] == 0) { ret = min(ret, query(id[mp(x[i],y[i])], id[mp(c[i],d[i])]) + w[i]); } } printf("Case #%d: %d ", ++cas, ret > 500000000 ? 0 : ret); } int main() { scanf("%d", &t); while (t --) { init(); ok(); } }