【JZOJ4887】【NOIP2016提高A组集训第13场11.11】最大匹配
2016-11-11 22:20
429 查看
题目描述
mhy12345学习了二分图匹配,二分图是一种特殊的图,其中的点可以分到两个集合中,使得相同的集合中的点两两没有连边。图的“匹配”是指这个图的一个边集,里面的边两两不存在公共端点。
匹配的大小是指该匹配有多少条边。
二分图匹配我们可以通过匈牙利算法得以在O(VE)时间复杂度内解决。
mhy12345觉得单纯的二分图匹配算法毫无难度,因此提出新的问题:
现在给你一个N个点N-1条边的连通图,希望你能够求出这个图的最大匹配以及最大匹配的数量。
两个匹配不同当且仅当存在一条边在第一个匹配中存在而在第二个匹配中不存在。
数据范围
分析与演绎
演绎直接得出树形动态规划。设f[i]表示取i的最大匹配数,F[i]为这个情况下的方案数;
g[i]表示不取i的最大匹配数,G[i]为这个情况下的方案数。
转移方程显然。
代码
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #define write(x) (cout<<(x)) #define writeln(x) (cout<<(x)<<endl) #define ll long long using namespace std; const char* fin="hungary.in"; const char* fout="hungary.out"; const ll inf=0x7fffffff; const ll maxn=100008,maxm=maxn*2,mo=1000000007; ll t,m,n,i,j,k; ll f[maxn],F[maxn],g[maxn],G[maxn],h[maxn],H[maxn]; ll fi[maxn],la[maxm],ne[maxm],tot=0; void add_line(ll a,ll b){ tot++; ne[tot]=fi[a]; la[tot]=b; fi[a]=tot; } ll read(){ ll x=0; char ch=getchar(); while (ch<'0' && ch>'9') ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } ll qpower(ll a,ll b){ ll c=1; while (b){ if (b&1) c=c*a%mo; a=a*a%mo; b>>=1; } return c; } ll N(ll a){ return qpower(a,mo-2); } void dfs(ll v,ll from){ ll i,j=0,k,sum=0,times=1; f[v]=0; F[v]=0; g[v]=0; G[v]=1; for (k=fi[v];k;k=ne[k]) if (la[k]!=from){ dfs(la[k],v); g[v]+=h[la[k]]; G[v]=G[v]*H[la[k]]%mo; sum+=h[la[k]]; times=times*H[la[k]]%mo; j=1; } for (k=fi[v];k;k=ne[k]){ if (la[k]!=from){ if (f[v]<sum-h[la[k]]+g[la[k]]+1){ f[v]=sum-h[la[k]]+g[la[k]]+1; F[v]=times*N(H[la[k]])%mo*G[la[k]]%mo; }else if (f[v]==sum-h[la[k]]+g[la[k]]+1) F[v]=(F[v]+times*N(H[la[k]])%mo*G[la[k]]%mo)%mo; } } if (f[v]>g[v]) h[v]=f[v],H[v]=F[v]; else if (f[v]<g[v]) h[v]=g[v],H[v]=G[v]; else h[v]=f[v],H[v]=(F[v]+G[v])%mo; } int main(){ freopen(fin,"r",stdin); freopen(fout,"w",stdout); t=read(); m=read(); while (t--){ tot=0; memset(fi,0,sizeof(fi)); n=read(); for (i=1;i<n;i++){ j=read(); k=read(); add_line(j,k); add_line(k,j); } dfs(1,0); write(h[1]); if (m==2) write(" "),write(H[1]); write(endl); } return 0; }
启发
写动态规划之前,一定要明确动态规划转移方程。相关文章推荐
- JZOJ4887. 【NOIP2016提高A组集训第13场11.11】最大匹配
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- 【JZOJ4886】【NOIP2016提高A组集训第13场11.11】字符串
- 【NOIP2016提高A组集训第13场11.11】字符串
- JZOJ4886【NOIP2016提高A组集训第13场11.11】字符串
- JZOJ 4823 【NOIP2016提高A组集训第1场10.29】小W学物理
- 【JZOJ4840】【NOIP2016提高A组集训第4场11.1】小W砍大树
- [jzoj]4883. 【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰(线段树优化DP)
- 【JZOJ 4866】 【NOIP2016提高组集训】禅与园林艺术
- JZOJ4870. 【NOIP2016提高A组集训第9场11.7】涂色游戏
- JZOJ4882. 【NOIP2016提高A组集训第12场11.10】多段线性函数
- 【JZOJ4883】【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰
- jzoj 4883. 【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰
- 【JZOJ4890】【NOIP2016提高A组集训第14场11.12】随机游走
- 【JZOJ4860】【NOIP2016提高A组集训第7场11.4】分解数
- JZOJ4868. 【NOIP2016提高A组集训第9场11.7】Simple
- JZOJ4883. 【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰 2017.10(B组)
- JZOJ4884. 【NOIP2016提高A组集训第12场11.10】图的半径