[CEOI2007] 树的匹配Treasury

时间:2022-09-21 08:09:11

类型:树形 DP

传送门:>Here<

题意:给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配是多少,并且计算出有多少种最大匹配。

解题思路

首先树形Dp是很明显的,$f[i][0]$表示$i$的子树中,$i$不参与匹配的最大匹配数,同样$f[i][1]$表示$i$参与匹配的最大匹配数。这样第一个子问题的答案就是$Max(f[1][0], f[1][1])$。

对于$f[i][0]$的转移很简单,既然$i$不参与匹配,那么$f[i][0]$就是它的每棵子树的最大匹配之和$$f[i][0]=\sum\limits_{ \ }Max(f[v][0],f[v][1])$$

对于$f[i][1]$,情况稍稍复杂一点。由于$i$节点最多只能被匹配一次,所以我们可以这样来考虑。对于节点$u$,选择其中一个子节点$v$来和自己匹配,剩余的仍然取最大值,这样剩余的最大值很显然是$f[u][0]-Max(f[v][0],f[v][1])$(刚才是用$Max(f[v][0],f[v][1])$推过来的),并且除了子节点$v$,$v$的其余儿子依然是独立的,所以再加上$f[v][0]$。所以转移方程即为$$f[u][1] = Max\{ f[u][0]-Max(f[v][0],f[v][1])+f[v][0]+1 \}$$

然后考虑第二个子问题,方案数怎么办?依然Dp。$g[i][k]$表示对应的$f[i][k]$的方案数。但注意了,答案不是$g[1][1]$,因为有可能$f[1][0]=f[1][1]$,这时候最大值有两个,所以答案可能是$g[1][0]+g[1][1]$。

还是先考虑$g[i][0]$如何转移,对于节点$u$,它由于是由各个子节点转移过来的,所以总的方案数就是各个子节点最大值方案数的积。还是一样,需要特判一下$g[v][0] =g[v][1]$的情况。

最难的也就是$g[i][1]$的转移了。对于这种情况,首先我们需要判断一下哪些节点与根匹配以后会转移出来最大值$f[u][1]$,而判断这个只需要按照前面的方程再推一遍看看是否相等就可以了。即$if(f[u][0]-Max(f[v][0],f[v][1])+f[v][0]+1 == f[u][1])$. 而这时候,我们还是仿照前面的思维过程,但是注意方案数中除去一部分使用除法而不是减法(前面是由乘法转移过来的),加上也要改成乘上。并且还是要特判$f[v][0]=f[v][1]的情况$。具体见代码。

想出上面这些并不复杂,而我却在$g$的初始化上卡了将近一小时。一开始我把每个$g[i][0]$和$g[i][1]$都初始化为$1$,结果挂了。调试千百遍之后把$g[i][1]$的初始化删掉以后突然就对了。这个现在我是这样理解的,因为我的$g[i][0]$是要拿去直接乘的,显然不能先赋成$0$,不然推出来的$g[i][0]$就全是$0$了。并且$g[i][1]$是加的,刚开始如果就是$1$就会影响结果。这个只不过是一个非常牵强的理解……

Code

高精度

/*written by -=qxz=- */
#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#define  INF  (0x3f3f3f3f)
#define  Max(a,b)  ((a) > (b) ? (a) : (b))
#define  Min(a,b)  ((a) < (b) ? (a) : (b))
#define  N  (1010)
typedef long long ll;
using namespace std;  

struct BigInteger {
    typedef unsigned long long ll;  

    ;
    ;
    vector<int> s;  

    BigInteger& clean(){)s.pop_back(); return *this;}
    BigInteger(ll num = ) {*this = num;}
    BigInteger(string s) {*this = s;}
    BigInteger& operator = (long long num) {
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } );
        return *this;
    }
    BigInteger& operator = (const string& str) {
        s.clear();
        ) / WIDTH + ;
        ; i < len; i++) {
            int end = str.length() - i*WIDTH;
            , end - WIDTH);
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return (*this).clean();
    }  

    BigInteger operator + (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        , g = ; ; i++) {
             && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    BigInteger operator - (const BigInteger& b) const {
        assert(b <= *this);
        BigInteger c; c.s.clear();
        , g = ; ; i++) {
             && i >= s.size() && i >= b.s.size()) break;
            int x = s[i] + g;
            if (i < b.s.size()) x -= b.s[i];
            ) {g = -; x += BASE;} ;
            c.s.push_back(x);
        }
        return c.clean();
    }
    BigInteger operator * (const BigInteger& b) const {
        int i, j; ll g;
        vector<ll> v(s.size()+b.s.size(), );
        BigInteger c; c.s.clear();
        ;i<s.size();i++) ;j<b.s.size();j++) v[i+j]+=ll(s[i])*b.s[j];
        , g = ; ; i++) {
             && i >= v.size()) break;
            ll x = v[i] + g;
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c.clean();
    }
    BigInteger operator / (const BigInteger& b) const {
        assert(b > );
        BigInteger c = *this;
        BigInteger m;
        ; i >= ; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return c.clean();
    }
    BigInteger operator % (const BigInteger& b) const {
        BigInteger c = *this;
        BigInteger m;
        ; i >= ; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return m;
    }  

    int bsearch(const BigInteger& b, const BigInteger& m) const{
        , R = BASE-, x;
        ) {
            x = (L+R)>>;
            )>m) return x; else L = x;}
            else R = x;
        }
    }
    BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
    BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
    BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
    BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
    BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;} 

    BigInteger& ; return *this;}
    BigInteger& ; return *this;}   

    bool operator < (const BigInteger& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        ; i >= ; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    bool operator >(const BigInteger& b) const{return b < *this;}
    bool operator<=(const BigInteger& b) const{return !(b < *this);}
    bool operator>=(const BigInteger& b) const{return !(*this < b);}
    bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
    bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
ostream& operator << (ostream& out, const BigInteger& x) {
    out << x.s.back();
    ; i >= ; i--) {
        ];
        sprintf(buf, "%08d", x.s[i]);
        ; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}
istream& operator >> (istream& in, BigInteger& x) {
    string s;
    if (!(in >> s)) return in;
    x = s;
    return in;
}
template <class T>
inline void read(T &x){
    , ch = ; x = ;
    ;
    ) + (x<<) + ch - ';
    if(f) x = -x;
}
int n,u,m,v;
vector <int> G[N];
];
BigInteger g[N][];
inline void AddEdge(int u, int v){
    G[u].push_back(v);
}
void DP(int u, int fa){
    ;
    ; i < sz; ++i){
        if(G[u][i] == fa) continue;
        ++not_leaf;
    }
    g[u][] = ;
    if(!not_leaf){
        return;
    }
    ; i < sz; ++i){
        v = G[u][i];
        if(v == fa) continue;
        DP(v,u);
        f[u][] += Max(f[v][], f[v][]);
        ] == f[v][]) g[u][] *= (g[v][] + g[v][]);
        else{
            ] > f[v][]) g[u][] *= g[v][];
            ] > f[v][]) g[u][] *= g[v][];
        }
    }
    f[u][] = f[u][];
    ; i < sz; ++i){
        v = G[u][i];
        if(v == fa) continue;
        f[u][] = Max(f[u][], f[u][]-Max(f[v][],f[v][])+f[v][]+);
    }
    ; i < sz; ++i){
        v = G[u][i];
        if(v == fa) continue;
        ]-Max(f[v][],f[v][])+f[v][]+ == f[u][]){
            ] == f[v][] && g[v][]+g[v][] != ){
                g[u][] += g[u][]/(g[v][]+g[v][])*g[v][];
            }
            else{
                ] > f[v][] && g[v][] != ){
                    g[u][] += g[u][]/(g[v][])*g[v][];
                }
                ] > f[v][] && g[v][] != ){
                    g[u][] += g[u][]/(g[v][])*g[v][];
                }
            }
        }
    }
}
int main(){
//    freopen(".in","r",stdin);
    read(n);
    ; i <= n; ++i){
        read(u);
        read(m);
        ; j <= m; ++j){
            read(v);
            AddEdge(u,v);
        }
    }
    DP(,);
    printf(][], f[][]));
    ][] == f[][]) cout << g[][]+g[][];
    else{
        ][] > f[][]) cout << g[][];
        ][] > f[][]) cout << g[][];
    }
    ;
}

[CEOI2007] 树的匹配Treasury的更多相关文章

  1. luogu P1623 &lbrack;CEOI2007&rsqb;树的匹配Treasury

    题目链接 luogu P1623 [CEOI2007]树的匹配Treasury 题解 f[i][0/1]表示当前位置没用/用了 转移暴力就可以了 code // luogu-judger-enable ...

  2. &lbrack;CEOI2007&rsqb;树的匹配Treasury&lpar;树形DP&plus;高精)

    题意 给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配. N≤1000,其中40%的数据答案不超过 108 题解 显然的树形DP+高精. 这题是作为考试题考 ...

  3. bzoj5123 &lbrack;Lydsy12月赛&rsqb;线段树的匹配

    题意: 线段树是这样一种数据结构:根节点表示区间 [1, n]:对于任意一个表示区间 [l, r] 的节点,若 l < r, 则取 mid = ⌊l+r/2⌋,该节点的左儿子为 [l, mid] ...

  4. 【bzoj5123】&lbrack;Lydsy12月赛&rsqb;线段树的匹配 树形dp&plus;记忆化搜索

    题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...

  5. CF308C-Sereja and Brackets-(线段树&plus;括号匹配)

    题意:给出一段括号,多次询问某个区间内能匹配多少括号. 题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val. 当前结点的val=左儿子的val+右儿子的val+min ...

  6. BZOJ5123 线段树的匹配(树形dp)

    线段树的任意一棵子树都相当于节点数与该子树相同的线段树.于是假装在树形dp即可,记忆化搜索实现,有效状态数是logn级别的. #include<iostream> #include< ...

  7. bzoj千题计划164:bzoj5123&colon; 线段树的匹配

    http://www.lydsy.com/JudgeOnline/upload/201712/prob12.pdf dp[len][0/1] 表示节点表示区间长度为len,节点选/不选的 最大匹配 s ...

  8. bzoj 5123&colon; &lbrack;Lydsy1712月赛&rsqb;线段树的匹配

    设f[0/1][x]为区间[1,x]的根向下 不选(0)或者选(1)  的dp pair<最优值,方案数>. 可以很容易的发现总状态数就是log级别的,因为2*n 与 (2*n+1 或者 ...

  9. Linux DTS&lpar;Device Tree Source&rpar;设备树详解之二&lpar;dts匹配及发挥作用的流程篇&rpar;【转】

    转自:https://blog.csdn.net/radianceblau/article/details/74722395 版权声明:本文为博主原创文章,未经博主允许不得转载.如本文对您有帮助,欢迎 ...

随机推荐

  1. mysql查询优化建议&lpar;百度&rpar;

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引.   2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使 ...

  2. 处理sevenzipsharp 检查密码函数的Bug

    using (SevenZipExtractor extr = new SevenZipExtractor(tbPackagePath.Text, "www.pc6.com")) ...

  3. oracle11g 修改字符集

    查看当前字符集SQL语句: select * from nls_database_parameters where parameter ='NLS_CHARACTERSET'; 修改字符集操作如下,首 ...

  4. 《怎样实现通过shell脚本将用户踢出系统》

    下面是一个将用户踢出系统的脚本: #!/bin/bashread -p "input your username " userps aux | grep "^$user& ...

  5. 取消Win7任务栏窗口自动排序

    点击“开始”菜单,在“搜索程序和文件”框中输入“关闭自动窗口排列”,找到后打开,找到“防止将窗口移动到屏幕边缘时自动排列窗口”这一项,勾上后点击确定就可以了.

  6. Bootstrap学习 - 全局CSS样式

    栅格Grid  <!-行(row)”必须包含在 .container (固定宽度)或 .container-fluid (100% 宽度)中-> <div class="c ...

  7. windows 查看端口是否被占用

    查看本机端口是否被占用:netstat -ano | findstr "端口号" 用此端口的pid查看是哪个程序在占用:tasklist|findstr "1896&qu ...

  8. JSch &colon; channel never closed or EOF 通道未关闭

    最近,我们的项目在开发远程节点管理的时候,使用了jsch库.在测试的时候发现有个节点在cmd执行完成之后,channel.isClosed()一直都是false,导致请求无法返回,但是其它有些节点就没 ...

  9. struts和hibernate整合

    程序示例: 1.引入jar包 2.实体对象 Dept.java package com.gqx.entity; import java.util.HashSet; import java.util.S ...

  10. hystrix -hystrixCommand配置介绍

    public @interface HystrixCommand { // HystrixCommand 命令所属的组的名称:默认注解方法类的名称 String groupKey() default ...