1 条题解
-
0
题意:
给一棵树,你可以匹配有边相连的两个点.
问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配。
题解:
显然,树形动态规划和高精的题。
这题是作为考试题考的,因为记得有一次考试,状态用两个数组存。
所以看到这题瞬间想到状态 代表以 为根的子树 点的最大匹配数。
代表以 为根的子树中 形成最大匹配的方案数。
然后方程改了很久,所以建议参考一下较长的代码。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const long long N=2000; long long dp[N][2],cnt,head[N],sum1[N],sum[N],n; struct num{ long long a[300],l; }z,f[N][3]; num add(num a,num b){ if(a.l<b.l)swap(a,b); for(long long i=1;i<=b.l;i++){ a.a[i]+=b.a[i]; } for(long long i=1;i<=a.l;i++) if(a.a[i]>=10){ a.a[i+1]+=1; a.a[i]-=10; if(i==a.l)a.l++; } return a; } num mul(num a,num b,num c){ for(long long i=1;i<=a.l;i++) for(long long j=1;j<=b.l;j++){ c.a[i+j-1]+=a.a[i]*b.a[j]; } long long top=0; for(long long i=1;i<=a.l+b.l;i++){ if(c.a[i])top=i; c.a[top+1]+=c.a[top]/10; c.a[top]%=10; } c.l=top; return c; } struct edge{ long long to,nxt; }e[N*2]; void add(long long u,long long v){ cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void getdp(long long u,long long fa){ long long sum=0; long long tmp=0; num tmpp; tmpp.a[1]=1; tmpp.l=1; for(long long i=head[u];i;i=e[i].nxt){ long long v=e[i].to; if(v==fa)continue; getdp(v,u); sum+=dp[v][1]; if(dp[v][0]==dp[v][1]&&dp[v][1])tmpp=mul(tmpp,add(f[v][0],f[v][1]),z); else tmpp=mul(tmpp,f[v][1],z); } dp[u][0]=sum; f[u][0]=tmpp; tmp=0; tmpp.a[1]=1; tmpp.l=1; for(long long i=head[u];i;i=e[i].nxt){ long long v=e[i].to; if(v==fa)continue; if(sum-dp[v][1]+dp[v][0]+1==tmp){ num tmppp=f[v][0]; for(long long j=head[u];j;j=e[j].nxt){ long long vv=e[j].to; if(vv==fa||v==vv)continue; if(dp[vv][0]==dp[vv][1]&&dp[vv][0])tmppp=mul(tmppp,add(f[vv][0],f[vv][1]),z); else tmppp=mul(tmppp,f[vv][1],z); } tmpp=add(tmpp,tmppp); } if(sum-dp[v][1]+dp[v][0]+1>tmp){ tmp=sum-dp[v][1]+dp[v][0]+1; tmpp=f[v][0]; for(long long j=head[u];j;j=e[j].nxt){ long long vv=e[j].to; if(vv==fa||v==vv)continue; if(dp[vv][0]==dp[vv][1]&&dp[vv][0])tmpp=mul(tmpp,add(f[vv][0],f[vv][1]),z); else tmpp=mul(tmpp,f[vv][1],z); } } } dp[u][1]=tmp; f[u][1]=tmpp; } void write(num x){ if(x.l==1&&x.a[1]==2){ cout<<1; return; } for(long long i=x.l;i>=1;i--){ printf("%lld",x.a[i]); } } int main(){ scanf("%lld",&n); for(long long i=1;i<=n;i++){ long long m,u; scanf("%lld%lld",&u,&m); for(long long j=1;j<=m;j++){ long long a; scanf("%lld",&a); add(u,a);add(a,u); } } getdp(1,0); if(dp[1][1]>dp[1][0]){ printf("%lld\n",dp[1][1]); write(f[1][1]); } else if(dp[1][1]<dp[1][0]){ printf("%lld\n",dp[1][0]); write(f[1][0]); } else { printf("%lld\n",dp[1][1]); write(add(f[1][0],f[1][1])); } return 0; }
- 1
信息
- ID
- 3610
- 时间
- 500ms
- 内存
- 32MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者