zoukankan      html  css  js  c++  java
  • CF 581F Contest Page 树形DP

    Description

    It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The election campaigns of both parties include numerous demonstrations on n main squares of the capital of Berland. Each of the n squares certainly can have demonstrations of only one party, otherwise it could lead to riots. On the other hand, both parties have applied to host a huge number of demonstrations, so that on all squares demonstrations must be held. Now the capital management will distribute the area between the two parties.

    Some pairs of squares are connected by (n - 1) bidirectional roads such that between any pair of squares there is a unique way to get from one square to another. Some squares are on the outskirts of the capital meaning that they are connected by a road with only one other square, such squares are called dead end squares.

    The mayor of the capital instructed to distribute all the squares between the parties so that the dead end squares had the same number of demonstrations of the first and the second party. It is guaranteed that the number of dead end squares of the city is even.

    To prevent possible conflicts between the zublicanes and the mumocrates it was decided to minimize the number of roads connecting the squares with the distinct parties. You, as a developer of the department of distributing squares, should determine this smallest number.

    Input

    The first line of the input contains a single integer n (2 ≤ n ≤ 5000) — the number of squares in the capital of Berland.

    Next n - 1 lines contain the pairs of integers x, y (1 ≤ x, yn, xy) — the numbers of the squares connected by the road. All squares are numbered with integers from 1 to n. It is guaranteed that the number of dead end squares of the city is even.

    Output

    Print a single number — the minimum number of roads connecting the squares with demonstrations of different parties.

    Sample Input

    Input

    8
    1 4
    2 4
    3 4
    6 5
    7 5
    8 5
    4 5

    Output

    1

    Input

    5
    1 2
    1 3
    1 4
    1 5

    Output

    2

    题目大意:有两个党派进行竞争选举,它们的拥护者要在n个广场上举行游行示威活动,已知这n个广场连成了一棵树,现在广场的管理员要对这n个广场进行分配,要求尽量满足以下条件:

    1、所有叶子节点必须平分给两个党派,已知叶子节点个数一定是偶数。

    2、要使两个党派之间连着的路的总个数尽量少,输出这个最少的路的个数。

    定义dp[i][j]:以i结点为根的子树中,把j个叶子节点分配给其中一个党派,此时两党派之间连着的路的最少个数。

    其它具体讲解看代码注释。

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    vector<int> adj[5013];
    int s[5013]; //当前节点为根的子树共有叶子的个数
    int dp[5013][5013];
    
    void solve(int x, int p=0) {
        s[x] = (adj[x].size()==1);
        for (int i: adj[x]) { //遍历vector中元素(c++11标准)
            if (i!=p)  {
                solve(i,x);
                s[x]+=s[i];
            }
        }
        for (int i=0;i<=n;i++) dp[x][i] = 1e9; //初始化最大值
        dp[x][0] = 0; //其中一个阵营拥有0个叶子,所以边为0条
        for (int i: adj[x])
            if (i!=p) {
                for (int j=s[x];j>=0;j--) //其中一个阵营拥有j个叶子,即将要计算dp[x][j]
                for (int u=0;u<=min(j,s[i]);u++) { //要使用到dp[i][u]的值
                    dp[x][j] = min(dp[x][j],dp[i][u]+dp[x][j-u]);
                    /*
                    这里的状态转移方程需要好好考虑一下,把i的访问顺序考虑进去就会大致明白,
                    这里的dp[x][j-u]是指在之前访问过的所有以i为根的子树中,分离出j-u个叶子节
                    点的最少边个数,这里考虑范围都仅限于访问过的以i为根子树,然后对于当前i子树,
                    根据之前的dp值,更新包含当前i子树的最少边个数。
    
                    比如:x的儿子节点有1 2 3 4 5
                    那么i的取值顺序是1 2 3 4 5
                    如果i取值到3,此时dp[x][y]表示的是1 2 这两颗子树中分离出y个叶子节点的最少边数。
                    所以j的值需要倒着取,以更新dp。
                    */
                }
            }
        for (int i=0;i<=s[x];i++)
            dp[x][s[x]-i] = min(dp[x][s[x]-i],1+dp[x][i]);//考虑与x根节点的关系
    }
    
    int main() {
        scanf("%d",&n);
        for (int i=1;i<n;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            adj[x].push_back(y);
            adj[y].push_back(x);
        }
        int root = 1;
        while (adj[root].size()==1) root++;
        solve(root);
        printf("%d
    ",n==2 ? 1 : dp[root][s[root]/2]);//要考虑没有根节点的情况
    
        return 0;
    }
  • 相关阅读:
    一. js高级(1)-面向对象编程
    tips01- 定位
    h5c3 part6 flex
    h5c3 part5 background and transform
    template and pagination
    h5c3 part4
    h5c3 part3
    h5c3 part2
    h5c3 part1
    学习博客
  • 原文地址:https://www.cnblogs.com/lastone/p/5349550.html
Copyright © 2011-2022 走看看