Topcoder SRM 721 Div.2 C. ApocalypseEasy

来源:互联网 发布:数据备份软件下载 编辑:程序博客网 时间:2024/06/14 02:50

C. ApocalypseEasy

Problem Statement

    We have an undirected tree with n nodes, numbered 0 through n-1. You are given its description: a vector p with n-1 elements. For each valid i, there is an edge between nodes p[i] and (i+1). There are k tokens on the tree, each in a different node. You are given a vector position. The elements of position are the numbers of the nodes that contain the tokens. A demon has placed k bombs onto the tree: one bomb into each node that currently contains a token. The bombs will all explode after t turns. If there is a token in a node with a bomb when the bomb explodes, the token is destroyed. Your task is to save as many tokens as possible. In each turn you can move each token at most once: from its current node to any adjacent node. During the turns each node may temporarily contain arbitrarily many tokens, even at the end of a turn. (See Example 4.) There is only one constraint: at the very end of the whole process (i.e., after turn t) each node must again contain at most one token. Compute and return the maximal number of tokens saved from the explosions.

Definition

Class:
    ApocalypseEasy
Method:
    maximalSurvival
Parameters:
    vector , vector , int
Returns:
    int
Method signature:
    int maximalSurvival(vector p, vector position, int t)
(be sure your method is public)

Limits

Time limit (s):
    2.000
Memory limit (MB):
    256
Stack limit (MB):
    256

Constraints

    n will be between 2 and 50, inclusive.
    p will contain exactly n-1 elements.
    For each i, 0 <= p[i] <= i.
    position will contain between 1 and n elements, inclusive.
    Each element in position will be between 0 and n-1, inclusive.
    Elements in position will be distinct.
    t will be between 1 and 50, inclusive.

Examples

0)
    {0,1,2}
    {2,3}
    1
    Returns: 1
    The tree is a line: 0 - 1 - 2 - 3.Initially, the tokens and the bombs are in the nodes 2 and 3.We have only one turn.Whatever we do, the token that starts on node 3 will be destroyed.We can save the other token by moving it from node 2 to node 1.
1)
    {0,1,2}
    {2,3}
    2
    Returns: 2
This is the same setting as in Example 0, but now we have two turns.
Now we can save both tokens.In the first turn we move the token from node 2 to node 1 and the token from node 3 to node 2.In the second turn we move the two tokens from 1 to 0 and from 2 to 1.
2)
    {0,0,0,1,2,3}
    {1,2,3}
    1
    Returns: 3
3)
    {0,1,2,3,4,5,6,7,8,9}
    {0,1,2,3,4,5,6}
    50
    Returns: 4
4)
    {0,0,0,0,0}
    {0,1,2}
    2
    Returns: 3
    This tree is a star: each of the nodes 1 through 5 is connected to node 0.Initially, nodes 0, 1, and 2 contain the tokens.We have two turns.One optimal solution looks as follows:In the first turn we move the tokens from nodes 1 and 2 into node 0.Thus, after the first turn all three tokens are in node 0.In the second turn we move the three tokens into the nodes 3, 4, and 5, respectively.Thus, we managed to save all three tokens.
5)
    {0}
    {0,1}
    1
    Returns: 0

题意

    给你一颗树,树上有一些节点上有令牌,在初始情况时,这些有令牌的节点上会被放上一个炸弹,这些炸弹在t时刻后将会爆炸,炸弹爆炸后会将该节点上的令牌炸毁,然后每一时刻你可以选择将每一个令牌移动到与它相邻的节点上,或者不动。问你在t时刻后最多可以救下多少令牌。

思路

    首先..这题在比赛的时候我被题意杀了,我没看清题以为在每一时刻前都会有新的炸弹出现在目前有令牌的节点。然后就一直想不出来怎么做,直到最后几分钟的时候我才看见炸弹只会出现在初始有令牌的节点上..(仿佛错过了一百个亿)。
    我首先存下一棵树,然后对于每个初始节点的令牌,我跑一次dfs搜出在t时刻内该令牌可以跑到的所有节点,之后与存有炸弹的节点的数组进行比较,如果有一个地方令牌可达并且炸弹炸不到的话,那么该令牌就可以存活。不然就ans–。

Code:

#include<bits/stdc++.h> typedef long long ll;using namespace std;bitset<55> reach[55],h;vector<int> G[55];bool vis[55][55];inline void dfs(int u,int step,int t,int pos) {    if(vis[u][step])        return;    vis[u][step]=1;    reach[pos][u]=1;    if(step==t)        return;    for(unsigned i=0;i<G[u].size();i++) {        int v=G[u][i];        dfs(v,step+1,t,pos);    }}class ApocalypseEasy {public:   int maximalSurvival( vector <int> p, vector <int> position, int t ) {        h.reset();        int n=p.size();        for(int i=0;i<=50;i++)            G[i].clear();        for(int i=0;i<n;i++) {            G[i+1].push_back(p[i]);            G[p[i]].push_back(i+1);        }        int ans=position.size();        for(int i=0;i<ans;i++)            h[position[i]]=1;        for(int i=0;i<position.size();i++) {            reach[i].reset();            memset(vis,0,sizeof vis);            dfs(position[i],0,t,i);            bitset<55> tmp=h&reach[i];            if(tmp.count()==reach[i].count())                ans--;            else {                for(int j=0;j<=n;j++)                    if(reach[i][j]&&!h[j]) {                        h[j]=1;                        break;                    }            }        }        return ans;   }};