NOIP模拟赛 最大匹配
2016-11-15 21:20
281 查看
问题描述
mhy12345学习了二分图匹配,二分图是一种特殊的图,其中的点可以分到两个集合中,使得相同的集合中的点两两没有连边。图的“匹配”是指这个图的一个边集,里面的边两两不存在公共端点。
匹配的大小是指该匹配有多少条边。
二分图匹配我们可以通过匈牙利算法得以在O(VE)时间复杂度内解决。
mhy12345觉得单纯的二分图匹配算法毫无难度,因此提出新的问题:
现在给你一个N个点N-1条边的连通图,希望你能够求出这个图的最大匹配以及最大匹配的数量。
两个匹配不同当且仅当存在一条边在第一个匹配中存在而在第二个匹配中不存在。
输入格式
第一行两个数T,P,其中T表示数据组数。接下来每组数据第一行一个数N
接下来N-1行每行两个数分别表示一条边。
输出格式
对于每组数据,输出一行:若p=1,则一行一个数输出图的最大匹配
若p=2,则一行两个数输出图的最大匹配以及最大匹配数量。
输入输出样例一
hungary.in | hungary.out |
1 1 2 1 2 | 1 |
问题可以看成层与层间、父亲和儿子间选和不选的两种情况
选一个节点可以看作选下图中的块:
约定如下:
f[i],选中编号为i的节点的最大匹配;
F[i],选中编号为i的节点的最大匹配的方案数;
g[i],不选编号为i的节点的最大匹配;
G[i],不选编号为i的节点的最大匹配的方案数;
h[i],编号为i节点的最大匹配;
H[i],编号为i节点的最大匹配的方案数;
于是初始的动规方程如下:
g[i]=g[i]+h[son]
G[i]=G[i]*H[son]
f[i]=max(f[i],(∑h[son,son])-h[son]+g[son])
F[i]=(∏H[son])/h[son]*G[son]
#include<stdio.h> #include<string.h> #define buf 100001 #define mo 1000000007 typedef long long ll; inline void S(int &x){ x=0;int c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; x*=f; } int n,fst[buf],nxt[buf<<1],v[buf<<1],tot; ll g[buf],G[buf],f[buf],F[buf],h[buf],H[buf]; inline void link(int a,int b){ v[++tot]=b, nxt[tot]=fst[a], fst[a]=tot, v[++tot]=a, nxt[tot]=fst[b], fst[b]=tot; } ll P(ll a,ll b){ ll c=1; for(;b;b>>=1){ if(b&1) c=c*a%mo; a=a*a%mo; } return c; } ll N(ll a){ return P(a,mo-2); } void D(int x,int fa){ G[x]=1; g[x]=f[x]=F[x]=h[x]=H[x]=0; ll mul=1,sum=0; for(int j=fst[x];j;j=nxt[j]) if(v[j]^fa) D(v[j],x), g[x]+=h[v[j]], G[x]=G[x]*H[v[j]]%mo, sum+=h[v[j]], mul=mul*H[v[j]]%mo; for(int j=fst[x];j;j=nxt[j]) if(v[j]^fa) if(f[x]<sum-h[v[j]]+g[v[j]]+1) f[x]=sum-h[v[j]]+g[v[j]]+1, F[x]=mul*N(H[v[j]])%mo*G[v[j]]%mo; else if(!(f[x]^(sum-h[v[j]]+g[v[j]]+1))) F[x]=(F[x]+mul*N(H[v[j]])%mo*G[v[j]]%mo)%mo; if(f[x]>g[x]) h[x]=f[x], H[x]=F[x]; else if(f[x]<g[x]) h[x]=g[x], H[x]=G[x]; else h[x]=f[x], H[x]=(F[x]+G[x])%mo; } int main(){ int T,p; freopen("hungary.in","r",stdin), freopen("hungary.out","w",stdout); S(T),S(p); while(T--){ tot=0; memset(fst,0,sizeof(fst)); S(n); for(int i=1,x,y;i<n;i++) S(x), S(y), link(x,y); D(1,0); if(p&1) printf("%I64d\n",h[1]); else printf("%I64d %I64d\n",h[1],H[1]); } fclose(stdin), fclose(stdout); }
相关文章推荐
- 【NOIP模拟赛】【乱搞AC】【贪心】【模拟】匹配
- noip 模拟赛 匹配 //贪婪策略
- (vijos 1892 noip 模拟 tree)<树形DP求树的最大匹配及方案数>
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- JZOJ4887. 【NOIP2016提高A组集训第13场11.11】最大匹配
- CJOJ 1943 【重庆八中模拟赛】寻找代表元(二分图最大匹配)
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- 【NOIP2016提高A组集训第13场11.11】最大匹配
- NOIP 模拟赛 最大子矩形 单调栈
- [jzoj]3457. 【NOIP2013模拟联考3】沙耶的玩偶(doll)(匈牙利-二分图最大匹配)
- 【JZOJ4887】【NOIP2016提高A组集训第13场11.11】最大匹配
- 1028 花店橱窗布置 (带权二分图的最大匹配)
- 带花树算法 UOJ#79. 一般图最大匹配
- [UOJ171][WC2016]挑战NPC-一般图最大匹配
- POJ 2446Chessboard(二分图最大匹配)
- 【数论】[NOIP模拟赛]无聊的计算
- 【二分图+最大匹配】北大 poj 3041 Asteroids
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
- poj The Perfect Stall 1274 (二分图最大匹配)
- 二分图最大匹配 最简单