[CEOI2007] 树的匹配Treasury
类型:树形 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的更多相关文章
- luogu P1623 [CEOI2007]树的匹配Treasury
题目链接 luogu P1623 [CEOI2007]树的匹配Treasury 题解 f[i][0/1]表示当前位置没用/用了 转移暴力就可以了 code // luogu-judger-enable ...
- [CEOI2007]树的匹配Treasury(树形DP+高精)
题意 给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配. N≤1000,其中40%的数据答案不超过 108 题解 显然的树形DP+高精. 这题是作为考试题考 ...
- bzoj5123 [Lydsy12月赛]线段树的匹配
题意: 线段树是这样一种数据结构:根节点表示区间 [1, n]:对于任意一个表示区间 [l, r] 的节点,若 l < r, 则取 mid = ⌊l+r/2⌋,该节点的左儿子为 [l, mid] ...
- 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索
题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...
- CF308C-Sereja and Brackets-(线段树+括号匹配)
题意:给出一段括号,多次询问某个区间内能匹配多少括号. 题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val. 当前结点的val=左儿子的val+右儿子的val+min ...
- BZOJ5123 线段树的匹配(树形dp)
线段树的任意一棵子树都相当于节点数与该子树相同的线段树.于是假装在树形dp即可,记忆化搜索实现,有效状态数是logn级别的. #include<iostream> #include< ...
- bzoj千题计划164:bzoj5123: 线段树的匹配
http://www.lydsy.com/JudgeOnline/upload/201712/prob12.pdf dp[len][0/1] 表示节点表示区间长度为len,节点选/不选的 最大匹配 s ...
- bzoj 5123: [Lydsy1712月赛]线段树的匹配
设f[0/1][x]为区间[1,x]的根向下 不选(0)或者选(1) 的dp pair<最优值,方案数>. 可以很容易的发现总状态数就是log级别的,因为2*n 与 (2*n+1 或者 ...
- Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇)【转】
转自:https://blog.csdn.net/radianceblau/article/details/74722395 版权声明:本文为博主原创文章,未经博主允许不得转载.如本文对您有帮助,欢迎 ...
随机推荐
- 设置placeholder无效解决办法
一.设置placeholder的方法 placeholder属性用来设置控件内部的提示信息 <input type="text" placeholder="请输入用 ...
- 插入排序专题 直接插入 折半 希尔shell
1.直接插入排序 分析:a[n]有n个元素 a[0...n-1] 从 i=1...n-1 a[i]依次与 a[0...n-2]数字进行比较 发现后面的数字大于前面的数字交换位置,每一次比较,与 ...
- 使用 Markdown编辑
作用: 学习笔记,整理日志, 发布日记,杂文,所见所想 撰写发布技术文稿(代码支持) 撰写发布学术论文(LaTeX 公式支持) sublime text3插件 输入 Shift + Ctrl + P, ...
- NFV组播实验对照
一 论文题目:Approximation and Online Algorithms for NFV-Enabled Multicasting in SDNs 发表时间:2017 期刊来源:Inter ...
- MySQL 5.7默认ONLY_FULL_GROUP_BY语义介绍
mysql 5.7版本 出现 ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corre ...
- MYSQL 表大小限制
MySQL 3.22限制的表大小为4GB.由于在MySQL 3.23中使用了MyISAM存储引擎,最大表尺寸增加到了65536TB(2567 – 1字节).由于允许的表尺寸更大,MySQL数据库的最大 ...
- react 路由 react-router-dom
import React from 'react'; import DataList from './data' import Tr from './Tr' // import One from '. ...
- lumen 5.6 设置APP_KEY为32位长的随机字符串
在 App\Console\Commands下 添加以下内容的KeyGenerateCommand.php文件 <?php namespace App\Console\Commands; use ...
- Html5使用canvas作图线宽很粗
自己使用canvas画图是碰到的问题,在这里记录一下.我把lineWidth设置为1,但是很粗,而且发虚.代码如下: <script type="text/javascript&quo ...
- 【知乎】WinForm 与 WPF的区别
你想上班 那么针对公司需求学如果只是自己写着玩 那么区分一下1.你的程序运行在 自己机器a.一个工具而已 要的是cooooooool 那么WPFb.一个工具而已 要的是useful easy 那么wi ...