hihocoder Tower Defense Game(树上贪心)
2016-08-05 09:50
225 查看
题目大意
给定一颗以1为根节点的树,每个节点有一个购入价格
p和卖出价格
q。
进入一个节点时需要花费
p,离开时可以收回
q,每个节点只产生一次购入和卖出。
请你选择一个遍历的顺序,要求在遍历的过程中身上的钱数不小于0,且出发时带的钱数最少。
按照遍历的顺序是指:当你选择了一颗子树之后,你需要将这个子树全部走完,才能选择其他子树。
解题思路
该题为一道树形图上的贪心问题。我们每一步的决策在于:当遍历到一个根时,对于其拥有的若干颗子树,应该以怎样的顺序来遍历这些子树。
先将问题简化为二叉树,并且两颗子树都只有根节点:
首先我们选择左边的路径,则需要携带的钱数为:
经过1:
L1 = p1
经过2:
L2 = p1-q1+p2
经过3:
L3 = p1-q1+p2-q2+p3
然后考虑走右边的情况:
经过1:
R1 = p1
经过3:
R2 = p1-q1+p3
经过2:
R3 = p1-q1+p3-q3+p2
对于这6个值,我们要求的是
min( max(L1, L2, L3), max(R1, R2, R3) )
由于在题目中已经明确说明总是有
p≥q,可以肯定有
L3≥R2,R3≥L2,所以可以直接将
L2和
R2排除。
又因为1是必经之路,因此在选择左右时,实际上需要比较的只有
L3和
R3。
我们将
L3和
R3换一种形式表示:
pSum = p1+p2+p3, qSum = q1+q2+q3,则
L3=pSum-qSum+q3,
R3=pSum-qSum+q2
若
L3>R3,则有
q3>q2,此时要选择的是
R3,即走右路;
若
L3<R3,则有
q2>q3,此时要选择的是
L3,即走左路。
由于
pSum和
qSum的值是确定的,因此实际上我们只需要根据
q2和
q3的值就可以选择走哪边。
最后的结论也就是:对于二叉树的情况,我们选择q值大的一边先走,一定能保证结果值最小
那么接下来将这个结论推广至多叉树的情况:
对于多叉树的情况,我们将子树按照q值从大到小的顺序,一定能保证结果值最小
这是由于q值之间的大小顺序是绝对的,假设3个子节点分别为
A,
B,
C,若
qA≥qB,
qB≥qC,则一定有
qA≥qC。
不妨举个例子:
根据q值,对应的6种遍历顺序分别为:
1,2,3:需要带钱8 1,3,2:需要带钱7 2,1,3:需要带钱8 2,3,1:需要带钱7 3,1,2:需要带钱7 3,2,1:需要带钱6
那么还有一个问题,一个节点的
p和
q是直接给定的,我们应该如何来求一颗子树的
pt和
qt(为了便于区分,我们将树的
p和
q记为
pt和
qt)?
在计算过程中,我们采用递归的从根节点开始遍历。在计算当前节点时,我们需要将其子树的
p和
q都先计算出来。
因此在计算当前子树时,我们已经知道了根节点的
p和
q,以及每颗子树的
pt和
qt(记作
pt1,pt2,pt3,...和
qt1,qt2,qt3,...,并且满足
qt1≥qt2≥qt3≥...)。
在该题中所有节点的总购买钱数不会超过200,000,000,不妨设置一个初始钱数
wallet = 200000000。
同时我们还需要一个值
minWallet,来记录钱包钱数最少时的值,初始也为200,000,000。
首先处理根节点:
wallet = wallet - p If (minWallet > wallet) Then minWallet = wallet End If wallet = wallet + q
接下来处理每个子树:
For i = 1 .. chdNumber wallet = wallet - pt[i] If (minWallet > wallet) Then minWallet = wallet End If wallet = wallet + qt[i] End For
最后可以得到整个树的
p和
q分别为:
pt[root] = 200000000 - minWallet // 遍历这颗树至少需要的钱数 qt[root] = wallet - minWallet // 最后的钱数-花费的钱数=返还的钱数
完整的伪代码为:
DFS(rt): wallet = 200000000 minWallet = 200000000 // 先递归处理每个子树 For each child i of rt DFS(i) End For // 对该根节点的所有子树按照qt值排序 sortByQt(children) // 处理根节点 wallet = wallet - p[rt] If (minWallet > wallet) Then minWallet = wallet End If wallet = wallet + q[rt] // 处理子树 For each child i of rt wallet = wallet - pt[i] If (minWallet > wallet) Then minWallet = wallet End If wallet = wallet + qt[i] End For // 记录子树 pt[rt] = 200000000 - minWallet qt[rt] = wallet - minWallet
最后所求的结果是
pt[1]。
由于在每一颗子树都使用了排序,最后这个算法的时间复杂度为O(NlogN),即使在
N为10000的数据下,也能够顺理通过。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 10005;
const int inf = 200000000;
struct Node
{
vector<int> child;
}tree[maxn];
int n,p[maxn],q[maxn];
int pt[maxn],qt[maxn];
bool cmp(int a,int b)
{
return qt[a] > qt[b];
}
void dfs(int u,int fa)
{
int Wallet = inf;
int minWallet = inf;
vector<int> V = tree[u].child;
for(int i = 0; i < V.size(); i++)
{
int v = V[i];
if(v == fa) continue;
dfs(v,u);
}
sort(V.begin(),V.end(),cmp);
Wallet = Wallet - p[u];
if(minWallet > Wallet)
minWallet = Wallet;
Wallet = Wallet + q[u];
for(int i = 0; i < V.size(); i++)
{
if(V[i] == fa) continue;
Wallet = Wallet - pt[V[i]];
if(minWallet > Wallet)
minWallet = Wallet;
Wallet = Wallet + qt[V[i]];
}
pt[u] = inf - minWallet;
qt[u] = Wallet - minWallet;
}
int main()
{
int u,v;
while(scanf("%d",&n)!=EOF)
{
for(int i = 1; i <= n; i++)
scanf("%d%d",&p[i],&q[i]);
for(int i = 1; i <= n; i++) tree[i].child.clear();
for(int i = 1; i < n; i++)
{
scanf("%d%d",&u,&v);
tree[u].child.push_back(v);
tree[v].child.push_back(u);
}
dfs(1,0);
printf("%d\n",pt[1]);
}
return 0;
}
相关文章推荐
- hihocoder1199 Tower Defense Game(树形dp)
- 【hihoCoder】Tower Defense Game
- hiho一下 第109周 Tower Defense Game 树DP+贪心
- HDU 5242 Game 【树上贪心 + 思维】
- some helpfuf web sit about tower defense game
- [AndEngine] GameSourceCode: Simple Tower Defense
- HDU5242:Game(树上贪心)
- HDU 5242 Game (树上贪心|类 树链剖分)
- HDU 4939 Stupid Tower Defense(贪心+dp)
- hiho一下 第109周:Tower Defense Game
- HDU 4939 Stupid Tower Defense(dp+贪心)
- hiho一下第109周《Tower Defense Game》
- BZOJ3426: Poi2013 Tower Defense Game
- 微软hiho上的笔试题:Tower Defense Game
- [POI2013]Tower Defense Game
- 湘潭大学OJ Defense Tower(贪心/优先队列)
- hihoCoder #1199 Tower Defense Game
- BZOJ3426 Poi2013 Tower Defense Game
- HihoCoder1653 : 公平分队([Offer收割]编程练习赛39)(贪心)
- HDU 4939 Stupid Tower Defense