您的位置:首页 > 运维架构

AOJ 2456 Usoperanto (树形dp)

2015-10-02 16:53 344 查看
题意:

N<=106单词,给出每个单词的单词字母个数,并给出N个单词之间的修饰关系

任意两个修饰单词与被修饰单词的花费 是中间夹着的所有单词的长度和

求如何安排单词之间的顺序, 使得任意两个修饰单词与被修饰单词花费的总和最小, 输出这个总和

分析:

对于多个修饰词同时修饰一个被修饰词的情况, 我们自然而然的考虑到一个贪心, 越排在外面的被算的次数越少, 显然从大到小排序计算.

问题来了 如果有嵌套多重修饰的情况 a−>b,bcf−>g 且b的大小是位于中间的, 那么之前的贪心就失效了.

那该怎么办呢 由于修饰关系构成了一棵树, 对于某一颗子树的修饰关系我们肯定是要一起考虑的, 不然就对别的子树有了更多的贡献, 这样结果是不优的.

考虑到这样,我们就可以树形dp了,dp[i]:=以i为根的子树修饰关系被处理完的最小花费

那么转移dp[u]=∑sonsi=0dp[v]+∑sonsi=0i∗sum[v](sum[v] is in decreasing order)

坑:

会爆栈 需要手动模拟递归 或者STL stack bfs模拟也可以

代码:

模拟递归

//
//  Created by TaoSama on 2015-10-02
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

typedef long long LL;

int fa
, cur
, head
, nxt
, pnt
, cnt;
void add_edge(int u, int v) {
pnt[cnt] = v;
nxt[cnt] = head[u];
head[u] = cnt++;
}

int stk
, top;

int n, val
, sum
, a
;
LL ans;

void calc(int u) {
int sz = 0;
for(int i = head[u]; ~i; i = nxt[i]) {
int v = pnt[i];
a[sz++] = sum[v];
}
sort(a, a + sz, greater<int>());
sum[u] = val[u];
for(int i = 0; i < sz; ++i) {
sum[u] += a[i];
ans += 1LL * i * a[i];
}
}

void dfs(int s) {
top = 0;
stk[++top] = s;
while(top) {
int u = stk[top];
if(~cur[u]) {
int &i = cur[u];
int v = pnt[i];
stk[++top] = v;
i = nxt[i];
} else {
calc(u);
--top;
}
}
}

int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d", &n) == 1) {
cnt = 0; memset(head, -1, sizeof head);
for(int v = 0; v < n; ++v) {
scanf("%d%d", val + v, fa + v);
if(~fa[v]) add_edge(fa[v], v);
}
ans = 0;
memcpy(cur, head, sizeof head);
for(int i = 0; i < n; ++i) {
if(fa[i] == -1) dfs(i);
}
printf("%lld\n", ans);
}
return 0;
}


STL stack bfs模拟

//
//  Created by TaoSama on 2015-10-02
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

vector<int> G
;

typedef long long LL;

int n, fa
, sum
;
LL dp
;

bool cmp(int x, int y) {
return sum[x] > sum[y];
}

void bfs(int root) {
queue<int> q;
stack<int> s;
q.push(root); s.push(root);
while(q.size()) {
int u = q.front(); q.pop();
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
q.push(v);
s.push(v);
}
}
while(s.size()) {
int u = s.top(); s.pop();
dp[u] = 0;
sort(G[u].begin(), G[u].end(), cmp);
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
dp[u] += dp[v] + 1LL * i * sum[v];
sum[u] += sum[v];
}
}
}

int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d", &n) == 1) {
for(int i = 0; i < n; ++i) G[i].clear();
for(int v = 0; v < n; ++v) {
scanf("%d%d", sum + v, fa + v);
if(~fa[v]) G[fa[v]].push_back(v);
}
LL ans = 0;
for(int i = 0; i < n; ++i) {
if(fa[i] == -1) {
bfs(i);
ans += dp[i];
}
}
printf("%lld\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息