模板題:
poj3164 Command Network
/***********************************\ * @prob: poj3164 Command Network * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 最小樹形圖 *\***********************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>#include <cmath>const int maxN = 110;const double INF = 1e198;double mp[maxN][maxN], x[maxN], y[maxN];bool del[maxN];int pre[maxN], root, n, m;template <typename _Tp>inline _Tp& gmax(_Tp& a, const _Tp& b){return a > b ? a : (a = b);}/* gmax */template <typename _Tp>inline _Tp& gmin(_Tp& a, const _Tp& b){return a < b ? a : (a = b);}/* gmin */template <typename _Tp>inline _Tp sqr(const _Tp& x) {return x * x;} /* sqr */inline bool connected(){ static const int SIZE = 0x3ffff; static int q[SIZE + 1]; static bool marked[maxN]; memset(marked, 0, sizeof marked); int f = 0, r = 0, u, v; for (q[r++] = 0; f - r;) for (marked[u = q[f++]] = true, f &= SIZE, v = 0; v < n; ++v) if (mp[u][v] < INF && !marked[v]) marked[q[r++] = v] = true, r &= SIZE; for (int i = 0; i < n; ++i) if (!marked[i]) return false; return true;} /* connected */inline int loop(){ pre[root = 0] = 0; for (int i = 0; i < n; ++i) if (!del[i] && i != root) { mp[i][i] = INF; pre[i] = i; for (int j = 0; j < n; ++j) if (!del[j] && mp[j][i] < mp[pre[i]][i]) pre[i] = j; } /* if */ for (int i = 0; i < n; ++i) if (!del[i] && i != root) { static bool vis[maxN]; memset(vis, 0, sizeof vis); int j = i; for (; !vis[j]; j = pre[j]) vis[j] = true; if (j == root) continue; else return j; } /* if */ return -1;} /* loop */inline void update(int t, double& ans){ ans += mp[pre[t]][t]; for (int i = pre[t]; i != t; i = pre[i]) ans += mp[pre[i]][i], del[i] = true; for (int i = 0; i < n; ++i) if (!del[i] && mp[i][t] < INF) mp[i][t] -= mp[pre[t]][t]; for (int j = pre[t]; j != t; j = pre[j]) for (int i = 0; i < n; ++i) if (!del[i]) { if (mp[i][j] < INF) gmin(mp[i][t], mp[i][j] - mp[pre[j]][j]); if (mp[j][i] < INF) gmin(mp[t][i], mp[j][i]); } /* for */ return;} /* update */inline double solve(){ memset(del, 0, sizeof del); double ans = 0; int j; while (~(j = loop())) update(j, ans); for (int i = 0; i < n; ++i) if (!del[i] && i != root) ans += mp[pre[i]][i]; return ans;} /* solve */int main(){ freopen("network.in" , "r", stdin ); freopen("network.out", "w", stdout); while (~scanf("%d%d", &n, &m)) { for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) mp[i][j] = INF; for (int i = 0; i < n; ++i) scanf("%lf%lf", x + i, y + i); while (m--) { int u, v; scanf("%d%d", &u, &v); --u, --v; mp[u][v] = sqrt(sqr(x[u] - x[v]) + sqr(y[u] - y[v])); } /* while */ if (!connected()) puts("poor snoopy"); else printf("%.2lf\n", solve()); } /* while */ return 0;} /* main *//*最小樹形圖模板題,不多說。*/
tju2248 Channel Design
/**********************************\ * @prob: tju2248 Channel Design * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 最小樹形圖 *\**********************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 110, maxM = 10010, INF = 0x3f3f3f3f;struct Edge{ int u, v, d; Edge(int u = 0, int v = 0, int d = 0): u(u), v(v), d(d) {} /* Edge */} edge[maxM];int n, m;int Directed_MST(int root, int n, int m){ int res = 0; for (;;) { static int In[maxN], pre[maxN], ID[maxN], vis[maxN]; memset(In, 0x3f, sizeof In); for (int j = 0; j < m; ++j) { int u = edge[j].u, v = edge[j].v, d = edge[j].d; if (u != v && d < In[v]) In[v] = d, pre[v] = u; } /* for */ for (int i = 0; i < n; ++i) if (i != root && In[i] == INF) return -1; memset(vis, 0xff, sizeof vis); memset(ID , 0xff, sizeof ID ); int cnt_v = 0; for (int i = 0; i < n; ++i) if (i != root) { res += In[i]; int u = i; for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u]) vis[u] = i; if (u != root && ID[u] == -1) { for (int v = pre[u]; v != u; v = pre[v]) ID[v] = cnt_v; ID[u] = cnt_v++; } /* if */ } /* if */ if (!cnt_v) break; for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++; for (int j = 0; j < m; ++j) { int v = edge[j].v; edge[j].u = ID[edge[j].u]; edge[j].v = ID[edge[j].v]; if (edge[j].u != edge[j].v) edge[j].d -= In[v]; } /* for */ n = cnt_v; root = ID[root]; } /* for */ return res;} /* Directed_MST */int main(){ freopen("design.in" , "r", stdin ); freopen("design.out", "w", stdout); while (~scanf("%d%d", &n, &m) && (n || m)) { int cnt_e = 0; while (m--) { int u, v, d; scanf("%d%d%d", &u, &v, &d); edge[cnt_e++] = Edge(--u, --v, d); } /* while */ int ans = Directed_MST(0, n, cnt_e); if (ans < 0) puts("impossible"); else printf("%d\n", ans); } /* while */ return 0;} /* main *//*最小樹形圖模板題,不多說。*/
UVa11183 Teen Girl Squad
/************************************\ * @prob: UVa11183 Teen Girl Squad * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 最小樹形圖 *\************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1010, maxM = 40010, INF = 0x3f3f3f3f;struct Edge {int u, v, d;} edge[maxM];int n, m, T;int Directed_MST(int root, int n, int m){ int res = 0; for (;;) { static int In[maxN], pre[maxN], ID[maxN], vis[maxN]; memset(In, 0x3f, sizeof In); for (int j = 0; j < m; ++j) { int u = edge[j].u, v = edge[j].v, d = edge[j].d; if (u != v && d < In[v]) In[v] = d, pre[v] = u; } /* for */ for (int i = 0; i < n; ++i) if (i != root && In[i] == INF) return -1; memset(ID , 0xff, sizeof ID ); memset(vis, 0xff, sizeof vis); int cnt_v = 0; for (int i = 0; i < n; ++i) if (i != root) { res += In[i]; int u = i; for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u]) vis[u] = i; if (ID[u] == -1 && u != root) { for (int v = pre[u]; v != u; v = pre[v]) ID[v] = cnt_v; ID[u] = cnt_v++; } /* if */ } /* if */ if (!cnt_v) break; for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++; for (int j = 0; j < m; ++j) { int v = edge[j].v; if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v])) edge[j].d -= In[v]; } /* for */ root = ID[root]; n = cnt_v; } /* for */ return res;} /* Directed_MST */int main(){ freopen("girl.in" , "r", stdin ); freopen("girl.out", "w", stdout); for (scanf("%d", &T); T--;) { scanf("%d%d", &n, &m); for (int i = 0; i < m; ++i) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].d); static int Case = 0; printf("Case #%d: ", ++Case); int ans = Directed_MST(0, n, m); if (ans < 0) puts("Possums!"); else printf("%d\n", ans); } /* for */ return 0;} /* main *//*最小樹形圖模板題,不多說。*/
無定根:
hdu2121 Ice_cream’s world II
/****************************************\ * @prob: hdu2121 Ice_cream’s world II * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 最小樹形圖 *\****************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1010, maxM = 11010;typedef long long int64;int64 INF = 0x3f3f3f3f3f3f3f3fLL;struct Edge {int u, v; int64 d;} edge[maxM];int n, m;int64 Directed_MST(int root, int n, int m, int& root_id){ int64 res = 0; for (;;) { static int pre[maxN], ID[maxN], vis[maxN]; static int64 In[maxN]; memset(In, 0x3f, sizeof In); for (int j = 0; j < m; ++j) { int u = edge[j].u, v = edge[j].v; int64 d = edge[j].d; if (u != v && d < In[v]) //!! { In[v] = d, pre[v] = u; if (u == root) root_id = j; } /* if */ } /* for */ for (int i = 0; i < n; ++i) if (i != root && In[i] == INF) return -1; memset(ID , 0xff, sizeof ID ); memset(vis, 0xff, sizeof vis); int cnt_v = 0; for (int i = 0; i < n; ++i) if (i != root) { res += In[i]; int u = i; for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u]) vis[u] = i; if (ID[u] == -1 && u != root) { for (int v = pre[u]; v != u; v = pre[v]) ID[v] = cnt_v; ID[u] = cnt_v++; } /* if */ } /* if */ if (!cnt_v) break; for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++; for (int j = 0; j < m; ++j) { int v = edge[j].v; if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v])) edge[j].d -= In[v]; } /* for */ root = ID[root]; n = cnt_v; } /* for */ return res;} /* Directed_MST */int main(){ freopen("Ice_cream.in" , "r", stdin ); freopen("Ice_cream.out", "w", stdout); while (~scanf("%d%d", &n, &m)) { int64 sum_d = 0; for (int i = 0; i < m; ++i) scanf("%d%d%lld", &edge[i].u, &edge[i].v, &edge[i].d), sum_d += edge[i].d; ++sum_d; int cnt_e = m, root_id = 0; for (int i = 0; i < n; ++i) edge[cnt_e].u = n, edge[cnt_e].v = i, edge[cnt_e++].d = sum_d; int64 ans = Directed_MST(n, n + 1, cnt_e, root_id) - sum_d; if (ans < 0 || ans >= sum_d) puts("impossible\n"); else printf("%lld %d\n\n", ans, root_id - m); } /* while */ return 0;} /* main *//*無定根的最小樹形圖。只需要加一個虛擬根,到所有點的權值恰好比所有原邊權值之和略大(這樣保證虛擬根只會與其中一個點連邊),並且再記錄一下根的位置就可以了(如果一個點的入邊為虛擬根,那麼這個點為“真實的”根)。要用long long類型。*/
(這並不是一道真正意義上的最小樹形圖:)
hdu3072 Intelligence System
/***************************************\ * @prob: hdu3072 Intelligence System * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 強連通分量 *\***************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>typedef long long int64;const int maxN = 50010, maxM = 100010;const int64 INF = 0x3f3f3f3f3f3f3f3fLL;struct Edge{ int u, v; int64 d; Edge* next; Edge() {} /* Edge */ Edge(int u, int v, int64 d, Edge* next): u(u), v(v), d(d), next(next) {} /* Edge */} __edge[maxM], *edge[maxN], *tot = __edge; bool marked[maxN];int Low[maxN], DFN[maxN], sta[maxN];int ID[maxN], n, m, Bcnt, Index, top;template <typename _Tp>inline _Tp& gmax(_Tp& a, const _Tp& b){return a > b ? a : (a = b);}/* gmax */template <typename _Tp>inline _Tp& gmin(_Tp& a, const _Tp& b){return a < b ? a : (a = b);}/* gmin */void Tarjan(int u){ DFN[u] = Low[u] = Index++; marked[sta[top++] = u] = true; for (Edge* p = edge[u]; p; p = p -> next) { if (DFN[p -> v] == -1) Tarjan(p -> v), gmin(Low[u], Low[p -> v]); else if (marked[p -> v]) gmin(Low[u], DFN[p -> v]); } /* for */ if (Low[u] == DFN[u]) { int tmp = u; do ID[tmp = sta[--top]] = Bcnt, marked[tmp] = false; while (tmp != u); ++Bcnt; } /* if */ return;} /* Tarjan */int main(){ freopen("Intelligence.in" , "r", stdin ); freopen("Intelligence.out", "w", stdout); while (~scanf("%d%d", &n, &m)) { memset(edge, 0, sizeof edge); tot = __edge; while (m--) { int u, v; int64 d; scanf("%d%d%lld", &u, &v, &d); edge[u] = new (tot++) Edge(u, v, d, edge[u]); } /* while */ memset(ID , 0xff, sizeof ID ); memset(DFN , 0xff, sizeof DFN ); memset(Low , 0xff, sizeof Low ); memset(marked, 0 , sizeof marked); Bcnt = top = Index = 0; Tarjan(0); static int64 In[maxN]; memset(In, 0x3f, sizeof In); for (Edge* p = __edge; p != tot; ++p) if (ID[p -> u] != ID[p -> v]) gmin(In[ID[p -> v]], p -> d); In[ID[0]] = 0; int64 ans = 0; for (int i = 0; i < Bcnt; ++i) ans += In[i]; printf("%lld\n", ans); } /* while */ return 0;} /* main *//*縮點,然後將所有最小入邊相加。*/
稍加變形:
hdu4009 Transfer water
/**********************************\ * @prob: hdu4009 Transfer water * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 25th, 2012 * * @memo: 最小樹形圖 *\**********************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1010, maxM = maxN * (maxN + 1), INF = 0x3f3f3f3f;struct Edge {int u, v, d;} edge[maxM];int x[maxN], y[maxN], z[maxN], n, m, X, Y, Z, cnt_e;inline int dist(int i, int j){return std::abs(x[i] - x[j]) + std::abs(y[i] - y[j]) + std::abs(z[i] - z[j]);}inline void Ins(int u, int v, int d){ edge[cnt_e].u = u; edge[cnt_e].v = v; edge[cnt_e].d = d; ++cnt_e; return;} /* Ins */int Directed_MST(int root, int n, int m){ int res = 0; for (;;) { static int pre[maxN], ID[maxN], vis[maxN]; static int In[maxN]; memset(In, 0x3f, sizeof In); for (int j = 0; j < m; ++j) { int u = edge[j].u, v = edge[j].v; int d = edge[j].d; if (u != v && d < In[v]) In[v] = d, pre[v] = u; } /* for */ for (int i = 0; i < n; ++i) if (i != root && In[i] == INF) return -1; memset(ID , 0xff, sizeof ID ); memset(vis, 0xff, sizeof vis); int cnt_v = 0; for (int i = 0; i < n; ++i) if (i != root) { res += In[i]; int u = i; for (; ID[u] == -1 && u != root && vis[u] != i; u = pre[u]) vis[u] = i; if (u != root && ID[u] == -1) //!! { for (int v = pre[u]; v != u; v = pre[v]) ID[v] = cnt_v; ID[u] = cnt_v++; } /* if */ } /* if */ if (!cnt_v) break; for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++; //!! for (int j = 0; j < m; ++j) { int v = edge[j].v; if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v])) edge[j].d -= In[v]; } /* for */ n = cnt_v; root = ID[root]; } /* for */ return res;} /* Directed_MST */int main(){ freopen("Transfer.in" , "r", stdin ); freopen("Transfer.out", "w", stdout); while (~scanf("%d%d%d%d", &n, &X, &Y, &Z) && (n || X || Y || Z)) { for (int i = 0; i < n; ++i) scanf("%d%d%d", x + i, y + i, z + i); cnt_e = 0; for (int i = 0, K, j; i < n; ++i) { scanf("%d", &K); while (K--) { scanf("%d", &j); --j; Ins(i, j, Y * dist(i, j) + (z[i] < z[j] ? Z : 0)); } /* while */ } /* for */ for (int i = 0; i < n; ++i) Ins(n, i, z[i] * X); int ans = Directed_MST(n, n + 1, cnt_e); if (ans < 0) puts("poor XiaoA"); else printf("%d\n", ans); } /* while */ return 0;} /* main *//*建立虛擬根,虛擬根到每個點的權值為該點自建水庫的費用。注意當i的海拔低於j時,仍然要算上Y的基本費用(Z為附加費用,而不是全部費用)。*/