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 }

 

posted @ 2013-08-10 21:54  zhsl  阅读(782)  评论(3编辑  收藏  举报