AcWing---病毒溯源---树状dp

3465. 病毒溯源 - AcWing题库

思路:

看到题,可以想到树,想到树就会想到递归,所以一般树状dp都是用递归来实现的。那么这道题的递推公式是什么呢,随便抓取一个点当做根节点,将g[i]定义为以i为根节点开始最长变异链的长度,将i的子节点即为j1,j2,j3...所以g[i]=max(g[j1],g[j2],g[j3]....)+1。g[j1],g[j2],g[j3],...就用递归来求即可。

这里树可以用数组来进行表示

可以参考博客:数组模拟邻接表 - AcWing

C++代码:

#include<bits/stdc++.h>
using namespace std;

int h[10010],e[10010],nxt[10010];
int idx;
int N;
int root[10010];//考察哪个点没有父节点
int head;
int path[10010];//最终路径上,节点i的下一个点

void add(int a,int b){
    e[idx]=b;//第idx条边的终点是b
    nxt[idx]=h[a]; //第idx条边的下一条边号为h[a]
    h[a]=idx; //h[a]指向idx这条新边
    idx++;
}

int dfs(int i){ //i为根节点,以节点i为根节点的最长变异链长度
    int res=0;
    if(h[i]==-1){return 1;}
    int v=0;
    /*树形dp大框架,遍历每条边*/
    for(int j=h[i];j!=-1;j=nxt[j]){
        int e_temp=e[j];
        int d_temp=dfs(e_temp);
        if(res<d_temp+1){
            res=d_temp+1;
            v=e_temp;
        }
        else if(res==d_temp+1 && v>e_temp){
            v=e_temp;
        }
    }
    path[i]=v;
    return res;
}


int main(){
    cin>>N;
    
    /*初始化h+path*/
    for(int i=0;i<N;i++){
        h[i]=-1;
        path[i]=-1;
    }
    /*建树*/
    for(int i=0;i<N;i++){
        int k;
        cin>>k;
        for(int j=0;j<k;j++){
            int temp;
            cin>>temp;
            add(i,temp);
            root[temp]=1;
        }
    }

    /*找树的根节点head*/
    for(int i=0;i<N;i++){
        if(root[i]==0){
            head=i;
            break;
        }
    }
    /*dfs*/
    cout<<dfs(head)<<endl;
    /*找路径*/
    cout<<head;
    for(int i=path[head];i!=-1;i=path[i]){
        cout<<' '<<i;
    }
    return 0;
    
}

Python代码:

import os
import sys
h=[-1]*10010
e=[0]*10010
nxt=[0]*10010
root=[0]*10010
path=[-1]*10010
idx=0
head=0
def add(a:int,b:int):
    global idx
    e[idx]=b
    nxt[idx]=h[a]
    h[a]=idx
    idx+=1
def dfs(i:int) -> int:
    res=0
    if h[i]==-1:
        return 1
    v=0
    j=h[i]
    while j!=-1:
        e_temp=e[j]
        d_temp=dfs(e_temp)
        if res<d_temp+1:
            res=d_temp+1
            v=e_temp
        elif res==d_temp+1 and v>e_temp:
            v=e_temp
        j=nxt[j]
    path[i]=v
    return res
N=int(input())

for i in range(N):
    k=list(map(int,input().split()))
    for j in range(1,k[0]+1):
        add(i,k[j])
        root[k[j]]=1
for i in range(N):
    if root[i]==0:
        head=i
        break
print(dfs(head))
end=[]
end.append(head)
i=path[head]
while i!=-1:
    end.append(i)
    i=path[i]
num=[str(i) for i in end]
print(' '.join(num))

这里需要注意几点:

1.在函数中用全局变量需要加global

2.打印0 2 4 6这种,且0之前6之后不能有空格,可以先将0 2 4 6放入list中,并且将这些元素转化成字符,用代码' '.join()来连接。

num=[str(i) for i in end]
print(' '.join(num))

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值