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模拟也可以
代码:
模拟递归
STL stack bfs模拟
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; }
相关文章推荐
- 树形DP 或 最小顶点覆盖=最大匹配(双向图)(HDU 1053)
- [BZOJ1017][JSOI2008][树形DP]魔兽地图DotR
- ZOJ3824 Fiber-optic Network
- hihocoder #1035 : 自驾旅行 III 树形DP
- POJ 3342
- URAL1018
- hdu1561 zoj3201
- poj 3107 Godfather
- zoj3201Tree of Tree
- Codeforces Round #135 (Div. 2)VD. Choosing Capital for Treeland
- POJ 1848 Tree
- 树形dp简单总结
- Party at Hali-Bula
- zoj cut the tree(树形dp,小细节真的很多)
- poj 2486 Apple Tree(树形dp)
- poj 1155 TELE(树形泛化背包dp)
- 树形DP
- HDU 1520 Anniversary party (树形dp) 解题报告
- POJ 1463 Strategic game (树形DP) 解题报告
- hdu 1561 树形dp+背包+dfs