贪心+拓扑排序 AOJ 2456 Usoperanto
题意:给出一条链,比如x连到y,x一定要在y的左边,且代价是这条链经过的点的权值和,问如何排序使得代价最小
分析:类似拓扑排序,先把入度为0的点入队,把指向该点的所有点按照权值排序,保证这样是代价是最小的,然后把这一块看成一个点继续入队。看图更简单:
/************************************************ * Author :Running_Time * Created Time :2015/10/3 星期六 13:02:41 * File Name :J.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int N = 1e6 + 10; const int E = 2e6 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const double EPS = 1e-8; struct Edge { int v, nex; }edge[E]; int fa[N], head[N], in[N]; int w[N], sta[N]; int n, e; ll ans; void init(void) { memset (head, -1, sizeof (head)); memset (in, 0, sizeof (in)); e = 0; } void add_edge(int u, int v) { edge[e].v = v; edge[e].nex = head[u]; head[u] = e++; } void BFS(void) { queue<int> Q; for (int i=0; i<n; ++i) { if (!in[i]) { Q.push (i); } } while (!Q.empty ()) { int u = Q.front (); Q.pop (); int tot = 0; for (int i=head[u]; ~i; i=edge[i].nex) { int v = edge[i].v; sta[tot++] = w[v]; } sort (sta, sta+tot); for (int i=0; i<tot; ++i) { ans += 1ll * sta[i] * (tot - i - 1); } if (fa[u] == -1) continue; w[fa[u]] += w[u]; if (! (--in[fa[u]])) { Q.push (fa[u]); } } } int main(void) { while (scanf ("%d", &n) == 1) { init (); for (int i=0; i<n; ++i) { scanf ("%d%d", &w[i], &fa[i]); if (fa[i] != -1) { in[fa[i]]++; add_edge (fa[i], i); } } ans = 0; BFS (); printf ("%lld\n", ans); } return 0; }
编译人生,运行世界!