1 条题解

  • 0
    @ 2026-2-4 23:20:56

    题意:

    给一棵树,你可以匹配有边相连的两个点.

    问你这棵树的最大匹配时多少,并且计算出有多少种最大匹配。

    题解:

    显然,树形动态规划和高精的题。

    这题是作为考试题考的,因为记得有一次考试,状态用两个数组存。

    所以看到这题瞬间想到状态 dp[i][0/1]dp[i][0/1] 代表以 ii 为根的子树 ii 点的最大匹配数。

    f[i][0/1]f[i][0/1] 代表以 ii 为根的子树中 ii 形成最大匹配的方案数。

    然后方程改了很久,所以建议参考一下较长的代码。

    代码:

    #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
    上传者