POJ1694 An Old Stone Game
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 2579 | Accepted: 1137 |
Description
There is an old stone game, played on an arbitrary general tree T. The goal is to put one stone on the root of T observing the following rules:
The player wins the game if by following the above rules, he succeeds to put one stone on the root of the tree.
You are to write a program to determine the least number of stones to be picked at the beginning of the game (K), so that the player can win the game on the given input tree.
- At the beginning of the game, the player picks K stones and puts them all in one bucket.
- At each step of the game, the player can pick one stone from the bucket and put it on any empty leaf.
- When all of the r immediate children of a node p each has one stone, the player may remove all of these r stones, and put one of the stones on p. The other r - 1 stones are put back into the bucket, and can be used in the later steps of the game.
The player wins the game if by following the above rules, he succeeds to put one stone on the root of the tree.
You are to write a program to determine the least number of stones to be picked at the beginning of the game (K), so that the player can win the game on the given input tree.
Input
The input describes several trees. The first line of this file is M, the number of trees (1 <= M <= 10). Description of these M trees comes next in the file. Each tree has N < 200 nodes, labeled 1, 2, ... N, and each node can have any possible number of children. Root has label 1. Description of each tree starts with N in a separate line. The following N lines describe the children of all nodes in order of their labels. Each line starts with a number p (1 <= p <= N, the label of one of the nodes), r the number of the immediate children of p, and then the labels of these r children.
Output
One line for each input tree showing the minimum number of stones to be picked in step 1 above, in order to win the game on that input tree.
Sample Input
2 7 1 2 2 3 2 2 5 4 3 2 6 7 4 0 5 0 6 0 7 0 12 1 3 2 3 4 2 0 3 2 5 6 4 3 7 8 9 5 3 10 11 12 6 0 7 0 8 0 9 0 10 0 11 0 12 0
Sample Output
3 4
Source
**********************************************************************
题目大意:在一棵树上面放石头,必须先放满一个节点的儿子才能才这个节点上放石头,当该节点的儿子都放满了,就可以把这些石头放回篮子,然后把一个石头放在这个节点上。问,要放到根节点最少需要多少个石头。
解题思路:第一次看到这道题目是在一次水水的比赛中,当时纠结了半天也没做出来。现在才想得通是树形dp。
要在一个节点上放石头,所需的最少的石头数,是跟他儿子有直接的关系。
首先,如果这个节点是叶子节点,那么dp[s]=1;
如果这个节点不是叶子节点,那么就需要模拟一下:首先取出它儿子中dp[t]最大的那个点,那么dp[s]的起始点就是dp[t],然后模拟篮子中还剩几个石头。把儿子都模拟出来就好了。
#include <stdio.h> #include <string.h> #include <vector> #include <queue> #define N 205 using namespace std; vector<int>gra[N]; int dp[N],n; void dfs(int s) { priority_queue<int>que; for(int i=0;i<gra[s].size();i++) { int t=gra[s][i]; dfs(t); que.push(dp[t]); } if(gra[s].size()==0) { dp[s]=1; return ; } int sum=que.top(),temp=sum-1; que.pop(); while(que.empty()==0) { int t=que.top(); que.pop(); if(temp>=t) temp=temp-1; else sum+=t-temp,temp=t-1; } dp[s]=sum; } void re(void) { scanf("%d",&n); for(int i=0;i<=n;i++) gra[i].clear(); for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&b); for(int j=1;j<=b;j++) { int c; scanf("%d",&c); gra[a].push_back(c); } } } void run(void) { dfs(1); printf("%d\n",dp[1]); } int main() { int ncase; scanf("%d",&ncase); while(ncase--) { re(); run(); } }