Vijos P1688 病毒传递

病毒传递

Description

小毒物想要让微生物世界里的所有细菌都感染上病毒。

微生物世界的等级观念很强,除了菌王外,每个细菌均有且只有一个直接的母体,菌王则没有母体。

如果细菌a是细菌b的母体,细菌b是细菌c的母体,则细菌a就是细菌c的母体。绝不会出现这样两个细菌a、b:细菌a是细菌b的母体,细菌b是细菌a的母体。

最开始的时刻为0,小毒物要做的就是用1个单位时间把病毒传递给某一个“病毒源细菌”,然后让细菌们自行传递。在任意一个单位时间中,任何一个已经被感染的细菌,都可以将病毒传递给它的一个直接母体或直接的下一个细菌。

现在,小毒物想知道的是:
1.最少需要多长时间,所有的细菌都会感染上病毒;
2.使感染时间最短时,可供选择的“病毒源细菌”有哪些。

Input

第一行一个数N。表示全部的细菌数。并且从1到N编上号,毒王为1。

第二行到第N行(共N-1行),每行一个数。第I行的数表示细菌I的直接母体的编号。

Output

第一行一个数。表示最后一个细菌被感染后的最早时间。

第二行若干个数。表示可供选择的“病毒源细菌”的编号。

Sample Input

8
1
1
1
2
2
3
7

Sample Output

5
1 2 3

Answer

/**
感觉这个题写的很垃圾
暴力每个点作为起点的时间,取最小值
设dp[i]为遍历完i的子树需要的时间
如果j是i的子树
那么肯定是先遍历dp[j]大的子树(这样传染过j点之后j能有更多的时间往下传)
so……………………
然而人家让输出时间我傻逼的输出了多少个方案居然也对了两个测试点…………………………
**/
#include 
   
   
    
    
#define maxn (1000 + 10)
#define inf (1 << 30) - 1
using namespace std;
vector
    
    
     
      V[maxn];

int dp[maxn];
bool vis[maxn];

void dfs(int p) {
    if(vis[p] == true)  return;
    if(V[p].size() == 1 && vis[V[p][0]] == true) {
        dp[p] = 0;
        return ;
    }
    if(dp[p] != 0)        return ;
    vis[p] = true;
    int temp[maxn];
    int l = 0;
    for(int i = 0; i < V[p].size(); i ++) {
        int q = V[p][i];
        if(vis[q] == false) {
            dfs(q);
            temp[l ++] = dp[q];
        }
    }
    sort(temp,temp + l);
    for(int i = 0; i < l; i ++) {
        dp[p] = max(dp[p],temp[i] + l - i);
    }
    vis[p] = false;
}

int re[maxn];

int main() {
//    freopen("in.txt","r",stdin);
    int n,mins = inf,cnt = 0;
    scanf("%d",&n);
    for(int i = 2; i <= n; i ++)  {
        int pre;
        scanf("%d",&pre);
        V[pre].push_back(i);
        V[i].push_back(pre);
    }
    for(int i = 1; i <= n; i ++) {
        memset(dp,0,sizeof(dp));
        memset(vis,false,sizeof(vis));
        dfs(i);
        re[i] = dp[i];
        mins = min(mins,re[i]);
    }
    for(int i = 1; i <= n; i ++) {
        if(re[i] == mins)   cnt ++;
    }
    printf("%d\n",mins + 1);
    for(int i = 1; i <= n; i ++) {
        if(re[i] == mins)   printf("%d ",i);
    }
    printf("\n");
    return 0;
}

    
    
   
   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值