贪心+拓扑排序 AOJ 2456 Usoperanto

时间:2022-08-04 18:21:20

题目传送门

题意:给出一条链,比如x连到y,x一定要在y的左边,且代价是这条链经过的点的权值和,问如何排序使得代价最小

分析:类似拓扑排序,先把入度为0的点入队,把指向该点的所有点按照权值排序,保证这样是代价是最小的,然后把这一块看成一个点继续入队。看图更简单:贪心+拓扑排序 AOJ 2456 Usoperanto

/************************************************
* 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;
}