POJ 1694 An Old Stone Game

 /*
先建树,然后对树进行后序遍历假设nodes[i].score表示以i为根的子树需要的石头数,则
(1)对于叶子节点其score为1
(2)对于非叶子节点,先将其所有子节点按照其所需score数降序排序,然后遍历其子节点
    int need = 0, rest = 0, need表示遍历到当前子树需要的石头数,rest表示剩下的石头数
  for( sid : i's sons)
      int sid = nodes[id].sons[k];
      //处理当前节点需要的数目
      int curNeed = nodes[sid].score  - rest;
      if(curNeed < 0) curNeed = 0;
      //更新需要的总数
      need += curNeed;
      //更新剩下的石头数
      rest = rest + curNeed - 1;
  则i节点需要的石头数即为need,返回即可
*/

#include <iostream>
#include <algorithm>
#define MAX_N 205
using namespace std;

struct node
{
    int id, score, sonNum;
    int sons[MAX_N + 1];
    node()
    {
        id = score = 0;
    }
}nodes[MAX_N + 1];
int n;

void init()
{
    for(int i = 1; i <= n; i++)
    {
        nodes[i].id = i;
        nodes[i].score = nodes[i].sonNum = 0;
    }
}

bool compare(const int n1, const int n2)
{
    if(nodes[n1].score >= nodes[n2].score) return true;
    else return false;
}

int getScore(int id)
{
    if(nodes[id].sonNum == 0) return nodes[id].score = 1;
    else
    {
        for(int s = 1; s <= nodes[id].sonNum; s++)
            getScore(nodes[id].sons[s]);
        sort(nodes[id].sons + 1, nodes[id].sons + 1 + nodes[id].sonNum, compare);
        int need = 0, rest = 0;
        for(int k = 1; k <= nodes[id].sonNum; k++)
        {
            int sid = nodes[id].sons[k];
            int curNeed = nodes[sid].score  - rest;
            if(curNeed < 0) curNeed = 0;
            need += curNeed;
            rest = rest + curNeed - 1;
        }
        return nodes[id].score = need;
    }
}
int main()
{
    int caseNum, i, j;
    scanf("%d", &caseNum);
    while(caseNum--)
    {
        init();
        scanf("%d", &n);
        for(i = 1; i <= n; i++)
        {
            int from, to, sn;
            scanf("%d%d", &from, &sn);
            for(j = 1; j <= sn; j++)
            {
                scanf("%d", &to);
                int p = ++nodes[from].sonNum;
                nodes[from].sons[p] = to;
            }
        }
        printf("%d/n", getScore(1));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值