HDU-4661 Message Passing 树形DP,排列组合
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661
题意:有n个人呈树状结构,每个人知道一个独特的消息。每次可以让一个人将他所知的所有消息告诉和他相邻的人。求所有人都知道所有消息花时花的步数最少的所有方案数。
首先需要满足的是最小的步数,所以我们一定是先把所有消息先传到一个人手中才是最优的,然后再从这个人传回去,也就是每条边走两次。我们只需要考虑单向传到某个人的方案数cnt,因为再传回去也是cnt。那么我们可以枚举每个点为收集点,把所有的和加起来就是答案。这里就是一个树形DP的问题,转移的时候是一个组合问题:记录f[u],cnt[u],f[u]为以u为根的子树的拓扑排序数,cnt[u]为以u为子树的节点个数。这里,涉及到如何合并两个子树,比如u的两个子树v1,v2,那么合并后的拓扑排序数为:f[u]=f[son1]*f[son2]*C(cnt[son1]+cnt[son2],cnt[son1]),也就是:
这里只求出了根节点的方案,还要再做一次搜索,把其它点的方案求出了,根据上面那个公式推一下就可以了。。。
1 //STATUS:C++_AC_3062MS_49796KB 2 #include <functional> 3 #include <algorithm> 4 #include <iostream> 5 //#include <ext/rope> 6 #include <fstream> 7 #include <sstream> 8 #include <iomanip> 9 #include <numeric> 10 #include <cstring> 11 #include <cassert> 12 #include <cstdio> 13 #include <string> 14 #include <vector> 15 #include <bitset> 16 #include <queue> 17 #include <stack> 18 #include <cmath> 19 #include <ctime> 20 #include <list> 21 #include <set> 22 #include <map> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,102400000") 25 //using namespace __gnu_cxx; 26 //define 27 #define pii pair<int,int> 28 #define mem(a,b) memset(a,b,sizeof(a)) 29 #define lson l,mid,rt<<1 30 #define rson mid+1,r,rt<<1|1 31 #define PI acos(-1.0) 32 //typedef 33 typedef __int64 LL; 34 typedef unsigned __int64 ULL; 35 //const 36 const int N=1000010; 37 const int INF=0x3f3f3f3f; 38 const LL MOD=1000000007,STA=8000010; 39 const LL LNF=1LL<<55; 40 const double EPS=1e-9; 41 const double OO=1e30; 42 const int dx[4]={-1,0,1,0}; 43 const int dy[4]={0,1,0,-1}; 44 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 45 //Daily Use ... 46 inline int sign(double x){return (x>EPS)-(x<-EPS);} 47 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} 48 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} 49 template<class T> inline T lcm(T a,T b,T d){return a/d*b;} 50 template<class T> inline T Min(T a,T b){return a<b?a:b;} 51 template<class T> inline T Max(T a,T b){return a>b?a:b;} 52 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} 53 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} 54 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} 55 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} 56 //End 57 58 LL fac[N],rev[N],f[N],cnt[N]; 59 int T,n; 60 LL ans; 61 vector<int> q[N]; 62 63 void exgcd(LL a,LL b,LL &d,LL &x,LL &y) 64 { 65 if(!b){d=a;x=1;y=0;} 66 else {exgcd(b,a%b,d,y,x);y-=x*(a/b);} 67 } 68 69 LL inv(LL a,LL n) 70 { 71 LL d,x,y; 72 exgcd(a,n,d,x,y); 73 return (x+n)%n; 74 } 75 76 void dfs1(int u,int fa) 77 { 78 int i,v; 79 cnt[u]=f[u]=1; 80 for(i=0;i<q[u].size();i++){ 81 if((v=q[u][i])==fa)continue; 82 dfs1(v,u); 83 cnt[u]+=cnt[v]; 84 f[u]=((f[u]*f[v])%MOD*rev[cnt[v]])%MOD; 85 } 86 f[u]=(f[u]*fac[cnt[u]-1])%MOD; 87 } 88 89 void dfs2(int u,int fa) 90 { 91 int i,v; 92 if(u!=1){ 93 f[u]=(f[fa]*cnt[u])%MOD*inv(n-cnt[u],MOD)%MOD; 94 ans=(ans+f[u]*f[u]%MOD)%MOD; 95 } 96 for(i=0;i<q[u].size();i++){ 97 if((v=q[u][i])==fa)continue; 98 dfs2(v,u); 99 } 100 } 101 102 int main(){ 103 // freopen("in.txt","r",stdin); 104 int i,j,a,b; 105 fac[0]=1; 106 for(i=1;i<N;i++)fac[i]=(i*fac[i-1])%MOD; 107 for(i=1;i<N;i++)rev[i]=inv(fac[i],MOD); 108 scanf("%d",&T); 109 while(T--) 110 { 111 scanf("%d",&n); 112 for(i=1;i<=n;i++)q[i].clear(); 113 for(i=1;i<n;i++){ 114 scanf("%d%d",&a,&b); 115 q[a].push_back(b); 116 q[b].push_back(a); 117 } 118 119 dfs1(1,0); 120 ans=f[1]*f[1]%MOD; 121 dfs2(1,0); 122 123 printf("%I64d\n",(ans+MOD)%MOD); 124 } 125 return 0; 126 }