10.26T2 树形DP

#3857 最大匹配

描述

小C学习了二分图匹配,二分图是一种特殊的图,其中的点可以分到两个集合中,使得相同的集合中的点两两没有连边。

图的“匹配”是指这个图的一个边集,里面的边两两不存在公共端点。

匹配的大小是指该匹配有多少条边。

二分图匹配我们可以通过匈牙利算法得以在O(VE)时间复杂度内解决。

小C觉得单纯的二分图匹配算法毫无难度,因此提出新的问题:

现在给你一个N个点N-1条边的连通图,希望你能够求出这个图的最大匹配以及最大匹配的数量。

两个匹配不同当且仅当存在一条边在第一个匹配中存在而在第二个匹配中不存在。

输入

第一行两个数T,P,其中T表示数据组数。

接下来每组数据第一行一个数N

接下来N-1行每行两个数分别表示一条边。

输出

对于每组数据,输出一行;

若p=1,则一行一个数输出图的最大匹配

若p=2,则一行两个数输出图的最大匹配以及最大匹配数量,答案对10^9+7取模。

样例输入[复制]
1 1
2
1 2
样例输出[复制]
1
提示
20181026153636_60601
 
 
 
 
第一问我写的全部点减去最大独立点集导致不能做第二问
粘个官方题解
 
code:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #define N 1000006
  5 using namespace std;
  6 const long long mod=1e9+7;
  7 struct node{
  8     long long u,v;
  9 }e[N];
 10 long long first[N],nxt[N],cnt;
 11 void add(long long u,long long v){
 12     e[++cnt].u=u;
 13     e[cnt].v=v;
 14     nxt[cnt]=first[u];
 15     first[u]=cnt;
 16 }
 17 long long f[N][2],rec[N],G[N][2];
 18 long long ksm(long long a,long long b){
 19     long long ans=1;
 20     for(;b;b>>=1){
 21         if(b&1){
 22             ans*=a;
 23             ans%=mod;
 24         }
 25         a*=a;
 26         a%=mod;
 27     }
 28     return ans;
 29 }
 30 long long Val(int x){
 31     if(f[x][1]>f[x][0])return G[x][1]%mod;
 32     if(f[x][1]<f[x][0])return G[x][0]%mod;
 33     return (G[x][1]+G[x][0])%mod;
 34 }
 35 void DP(long long x,long long father){
 36     G[x][0]=1,G[x][1]=0;
 37     for(long long i=first[x];i;i=nxt[i]){
 38         long long v=e[i].v;
 39         if(v==father)continue;
 40         DP(v,x);
 41         f[x][0]+=max(f[v][0],f[v][1])%mod;
 42         if(f[v][0]>f[v][1]){
 43             G[x][0]*=G[v][0];
 44             G[x][0]%=mod;
 45         } 
 46         else if(f[v][0]<f[v][1]){
 47             G[x][0]*=G[v][1];
 48             G[x][0]%=mod;
 49         }
 50         else if(f[v][0]==f[v][1]){
 51             G[x][0]*=(G[v][0]+G[v][1])%mod;
 52             G[x][0]%=mod;
 53         }
 54     }
 55     for(long long i=first[x];i;i=nxt[i]){
 56         long long v=e[i].v;
 57         if(v==father)continue;
 58         f[x][1]=max(f[x][1],f[x][0]-max(f[v][0],f[v][1])+f[v][0]+1);
 59     }
 60     for(long long i=first[x];i;i=nxt[i]){
 61         long long v=e[i].v;
 62         if(v==father)continue;
 63         if(f[x][1]==f[x][0]-max(f[v][0],f[v][1])+f[v][0]+1){
 64             G[x][1]=(G[x][1]+(G[v][0]*G[x][0]%mod*ksm(Val(v),mod-2))%mod)%mod;
 65         }
 66     }
 67 }
 68 void init(){
 69     memset(first,0,sizeof first);
 70     memset(nxt,0,sizeof nxt);
 71     memset(e,0,sizeof e);
 72     memset(f,0,sizeof f);
 73     memset(G,0,sizeof G);
 74     memset(rec,0,sizeof rec);
 75     cnt=0;
 76 }
 77 long long read(){
 78     long long x=0,f=1;
 79     char c=getchar();
 80     while(!isdigit(c)){
 81         if(c=='-')f=-1;
 82         c=getchar();
 83     }
 84     while(isdigit(c)){
 85         x=(x<<3)+(x<<1)+c-'0';
 86         c=getchar();
 87     }
 88     return x*f;
 89 }
 90 signed main(){
 91 //    cout<<ksm(3,5);
 92 //    freopen("hungary.in","r",stdin);
 93     long long T,P;
 94     T=read(),P=read();
 95     while(T--){
 96         init();
 97         long long n;n=read();
 98         for(long long i=1;i<n;i++){
 99             long long a,b;
100             a=read(),b=read();
101             add(a,b);
102             add(b,a);
103         }
104         DP(1,1);
105         cout<<max(f[1][0],f[1][1]);
106         if(P==2){
107             cout<<" ";
108             if(f[1][0]>f[1][1])cout<<G[1][0];
109             else if(f[1][0]<f[1][1])cout<<G[1][1];
110             else cout<<(G[1][1]+G[1][0])%mod;
111         }
112         cout<<'
';
113     } 
114     return 0;
115 }

over

原文地址:https://www.cnblogs.com/saionjisekai/p/9858465.html