• [BZOJ 1907] 树的路径覆盖 【树形DP】


    题目链接:BZOJ - 1907

    题目分析

    使用树形 DP,f[x][0] 表示以 x 为根的子树不能与 x 的父亲连接的最小路径数(即 x 是一个折线的拐点)。

    f[x][1] 表示以 x 为根的子树可以与 x 的父亲连接的最小路径数。

    转移的方式非常巧妙,Orz PoPoQQQ 的 blog 。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const int MaxN = 10000 + 5;
    
    int T, n;
    int f[MaxN][2];
    
    struct Edge
    {
    	int v;
    	Edge *Next;
    } E[MaxN * 2], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y)
    {
    	++P; P -> v = y;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    
    void Solve(int x, int Fa)
    {
    	f[x][0] = f[x][1] = 1;
    	int Temp = 0;
    	for (Edge *j = Point[x]; j; j = j -> Next)
    	{
    		if (j -> v == Fa) continue;
    		Solve(j -> v, x);
    		f[x][0] = gmin(f[x][0] + f[j -> v][0], f[x][1] + f[j -> v][1] - 1);
    		f[x][1] = gmin(f[x][1] + f[j -> v][0], Temp + f[j -> v][1]);
    		Temp += f[j -> v][0];
    	}
    }
    
    int main()
    {
    	scanf("%d", &T);
    	for (int Case = 1; Case <= T; ++Case)
    	{
    		memset(E, 0, sizeof(E)); P = E;
    		memset(Point, 0, sizeof(Point));
    		scanf("%d", &n);
    		int a, b;
    		for (int i = 1; i <= n - 1; ++i)	
    		{
    			scanf("%d%d", &a, &b);
    			AddEdge(a, b);
    			AddEdge(b, a);
    		}
    		Solve(1, 0);
    		printf("%d
    ", f[1][0]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    关于ping github.com超时的解决办法
    git使用过程中的若干问题笔记
    PAT甲级1017题解——模拟排序
    第七章4
    第七章3
    第七章2
    第七章1
    第六章4
    第六章3
    第六章2
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4425219.html
Copyright © 2020-2023  润新知