题意
给一棵树,你可以匹配有边相连的两个点,问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配。
N≤1000,其中40%的数据答案不超过 108
题解
显然的树形DP+高精。
这题是作为考试题考的,因为记得有一次考试,状态用两个数组存。
所以看到这题瞬间想到状态dp[i][0/1]代表以i为根的子树不选/选i点的最大匹配数。
f[i][0/1]代表以i为根的子树中不选/选i形成最大匹配的方案数。
然后方程改了半天:而且极长所以看代码吧。
TM还要加高精。。。
(第一个点挂了,特判过的)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const long long N=2000; 8 long long dp[N][2],cnt,head[N],sum1[N],sum[N],n; 9 struct num{ 10 long long a[300],l; 11 }z,f[N][3]; 12 num add(num a,num b){ 13 if(a.l<b.l)swap(a,b); 14 for(long long i=1;i<=b.l;i++){ 15 a.a[i]+=b.a[i]; 16 } 17 for(long long i=1;i<=a.l;i++) 18 if(a.a[i]>=10){ 19 a.a[i+1]+=1; 20 a.a[i]-=10; 21 if(i==a.l)a.l++; 22 } 23 return a; 24 } 25 num mul(num a,num b,num c){ 26 for(long long i=1;i<=a.l;i++) 27 for(long long j=1;j<=b.l;j++){ 28 c.a[i+j-1]+=a.a[i]*b.a[j]; 29 } 30 long long top=0; 31 for(long long i=1;i<=a.l+b.l;i++){ 32 if(c.a[i])top=i; 33 c.a[top+1]+=c.a[top]/10; 34 c.a[top]%=10; 35 } 36 c.l=top; 37 return c; 38 } 39 struct edge{ 40 long long to,nxt; 41 }e[N*2]; 42 void add(long long u,long long v){ 43 cnt++; 44 e[cnt].nxt=head[u]; 45 e[cnt].to=v; 46 head[u]=cnt; 47 } 48 void getdp(long long u,long long fa){ 49 long long sum=0; 50 long long tmp=0; 51 num tmpp; 52 tmpp.a[1]=1; 53 tmpp.l=1; 54 for(long long i=head[u];i;i=e[i].nxt){ 55 long long v=e[i].to; 56 if(v==fa)continue; 57 getdp(v,u); 58 sum+=dp[v][1]; 59 if(dp[v][0]==dp[v][1]&&dp[v][1])tmpp=mul(tmpp,add(f[v][0],f[v][1]),z); 60 else tmpp=mul(tmpp,f[v][1],z); 61 } 62 dp[u][0]=sum; 63 f[u][0]=tmpp; 64 tmp=0; 65 tmpp.a[1]=1; 66 tmpp.l=1; 67 for(long long i=head[u];i;i=e[i].nxt){ 68 long long v=e[i].to; 69 if(v==fa)continue; 70 if(sum-dp[v][1]+dp[v][0]+1==tmp){ 71 num tmppp=f[v][0]; 72 for(long long j=head[u];j;j=e[j].nxt){ 73 long long vv=e[j].to; 74 if(vv==fa||v==vv)continue; 75 if(dp[vv][0]==dp[vv][1]&&dp[vv][0])tmppp=mul(tmppp,add(f[vv][0],f[vv][1]),z); 76 else tmppp=mul(tmppp,f[vv][1],z); 77 } 78 tmpp=add(tmpp,tmppp); 79 } 80 if(sum-dp[v][1]+dp[v][0]+1>tmp){ 81 tmp=sum-dp[v][1]+dp[v][0]+1; 82 tmpp=f[v][0]; 83 for(long long j=head[u];j;j=e[j].nxt){ 84 long long vv=e[j].to; 85 if(vv==fa||v==vv)continue; 86 if(dp[vv][0]==dp[vv][1]&&dp[vv][0])tmpp=mul(tmpp,add(f[vv][0],f[vv][1]),z); 87 else tmpp=mul(tmpp,f[vv][1],z); 88 } 89 } 90 } 91 dp[u][1]=tmp; 92 f[u][1]=tmpp; 93 } 94 void write(num x){ 95 if(x.l==1&&x.a[1]==2){ 96 cout<<1; 97 return; 98 } 99 for(long long i=x.l;i>=1;i--){ 100 printf("%lld",x.a[i]); 101 } 102 } 103 int main(){ 104 scanf("%lld",&n); 105 for(long long i=1;i<=n;i++){ 106 long long m,u; 107 scanf("%lld%lld",&u,&m); 108 for(long long j=1;j<=m;j++){ 109 long long a; 110 scanf("%lld",&a); 111 add(u,a);add(a,u); 112 } 113 } 114 getdp(1,0); 115 if(dp[1][1]>dp[1][0]){ 116 printf("%lld ",dp[1][1]); 117 write(f[1][1]); 118 } 119 else if(dp[1][1]<dp[1][0]){ 120 printf("%lld ",dp[1][0]); 121 write(f[1][0]); 122 } 123 else { 124 printf("%lld ",dp[1][1]); 125 write(add(f[1][0],f[1][1])); 126 } 127 return 0; 128 }