目录
285. 没有上司的舞会 - 以u为根的子树中,01选择u点
1072. 树的最长路径 - 最长路径+次长路径
323. 战略游戏 - 以u为根的子树中,01选择u点
1220. 生命之树
活动 - AcWing
题目:
选了某个节点就不能选其父节点和子节点,求最大权值和
思路:
- f[u][0]为所有以u为根的子树中选择,且不选择u这个节点的最大快乐值
- f[u][1]为所有以u为根的子树中选择,且选择u这个节点的最大快乐值
找到根节点,向下dfs
遍历与该节点u相邻的节点
- 不选该节点,则它的子树可以选or不选
- 如果选该节点,则它的子树都不能选
答案就是max(f[root][0],f[root][1])
import java.util.*;
class Main
{
static int N=6010;
static int[] h=new int[N],ne=new int[N],e=new int[N];
static int idx;
static int[] w=new int[N];
static boolean[] st=new boolean[N]; //记录有父节点的点
static int[][] f=new int[N][2];
public static void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
public static void dfs(int u)
{
f[u][1]=w[u]; //选这个根节点的话
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
dfs(j);
f[u][0]+=Math.max(f[j][1],f[j][0]); //如果不选这个根节点 则子树有选or不选两种选择
f[u][1]+=f[j][0]; //如果选这个根节点 则子树只能不选
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
for(int i=1;i<=n;i++) w[i]=sc.nextInt();
Arrays.fill(h,-1);
for(int i=0;i
活动 - AcWing
题目:
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值
在树中找到一条路径,使得使得路径两端的点的距离最远
输出树的最长路径长度
思路:
- f[0][i]是以节点i为根的子树中,从子树的某个节点到i的最长路径
- f[1][i]是以节点i为根的子树中,从子树的某个节点到i的次长路径
则答案就是最大的最长路径和次长路径之和 res=max(f[0][i]+f[1][i])
初始选取任意点作为根节点dfs,这样整颗树的拓扑结构被唯一确定
对于每一个节点u,遍历它的相邻的子节点
- 如果子节点的最长路+w[i] > 当前最长路,则更新最长路和次长路
- 否则如果>当前次长路,则更新次长路
答案res更新以u为根节点的最长路径长度
import java.util.*;
class Main
{
static int N=10010,M=N<<1;
static int[][] f=new int[2][N];
static int[] h=new int[N],ne=new int[M],e=new int[M],w=new int[M];
static int res,idx,n;
public static void add(int a,int b,int c)
{
e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
public static void dfs(int u,int father)
{
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==father) continue; //只遍历相邻子节点
dfs(j,u); //先探子树
if(f[0][j]+w[i]>f[0][u])
{
f[1][u]=f[0][u]; //u的次长路=之前的最长路
f[0][u]=f[0][j]+w[i];
}
else if(f[0][j]+w[i]>f[1][u]) f[1][u]=f[0][j]+w[i];
}
res=Math.max(res,f[1][u]+f[0][u]);
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
Arrays.fill(h,-1);
n=sc.nextInt();
for(int i=0;i
活动 - AcWing
题目:
给定一棵包含 n 个结点的树,以及树上的 n−1 条边
我们需要在这 n 个结点中,选择一定数量的结点放上哨兵
最终要求,树中任意 n−1 条边的左右两端,至少有一个结点上放置了哨兵
求解一个方案,该方案满足上述要求,且放置的哨兵数量最少,输出该方案放置的哨兵数量
思路:
这题和上面那道【没有上司的舞会】是一个类型
都是选取某个点为根节点的子树,看选不选这个点的xx值
- f[i][0]以i为根节点的子树 i这个节点不放哨兵的最小士兵数
- f[i][1]以i为根节点的子树 i这个节点不放哨兵的最小士兵数
- 如果当前节点u放了哨兵,则子树中连向u的另一端,可以放也可以不放
- f[u][1]+=max( f[j][1],f[j][0] )
- 如果当前节点没放哨兵,则子树中连向u的另一端,必须放
- f[u][0]+=f[j][1]
找到根节点,从根节点向下dfs
答案就是max(f[root][0],f[root][1])
import java.util.*;
class Main
{
static int N=1600;
static int[] st=new int[N];
static int[] h=new int[N],ne=new int[N],e=new int[N];
static int[][] f=new int[N][2];
//f[i][0]以i为根节点的子树 i这个节点不放哨兵的最小士兵数
//f[i][1]以i为根节点的子树 i这个节点不放哨兵的最小士兵数
static int n,idx;
public static void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
public static void dfs(int u)
{
f[u][1]=1; //放哨兵的话
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
dfs(j);
f[u][0]+=f[j][1];
f[u][1]+=Math.min(f[j][1],f[j][0]);
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
Arrays.fill(st,0);
Arrays.fill(h,-1);
for(int i=0;i0)
{
int x=sc.nextInt();
st[x]=1;
add(id,x);
}
}
int root=0;
while(st[root]==1) root++;
dfs(root);
System.out.println(Math.min(f[root][0],f[root][1]));
}
}
}
活动 - AcWing
题目:
求树上连通块的最大和
思路:
f[i]以i为根的子树(包含i)的连通块的最大和
初始选取任意点作为根节点dfs,这样整颗树的拓扑结构被唯一确定
对于每一个节点u,遍历它的相邻的子节点:
每次累加子树的连通块最大和,如果小于0就不加
最后遍历所有节点,看以哪个节点做根连通块和最大
import java.util.*;
class Main
{
static int N=100010,M=N*2;
static long[] f=new long[N]; //f[i]以i为根的子树(包含i)的连通块的最大和
static int[] h=new int[N],ne=new int[M],e=new int[M],w=new int[N];
static int idx,n;
public static void add(int a,int b)
{
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
public static void dfs(int u,int father)
{
f[u]=w[u];
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==father) continue;
dfs(j,u);
f[u]+=Math.max((long)0,f[j]);
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
Arrays.fill(h,-1);
n=sc.nextInt();
for(int i=1;i<=n;i++) w[i]=sc.nextInt();
int t=n-1;
while(t-->0)
{
int a=sc.nextInt(),b=sc.nextInt();
add(a,b); add(b,a);
}
dfs(1,-1);
long res=-0x3f3f3f3f;
for(int i=1;i<=n;i++) res=Math.max(res,f[i]);
System.out.print(res);
}
}