Message Passing

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 1187    Accepted Submission(s): 423

Problem Description
There are n people numbered from 1 to n. Each people have a unique message. Some pairs of people can send messages directly to each other, and this relationship forms a structure of a tree. In one turn, exactly one person sends all
messages s/he currently has to another person. What is the minimum number of turns needed so that everyone has all the messages?


This is not your task. Your task is: count the number of ways that minimizes the number of turns. Two ways are different if there exists some k such that in the k-th turn, the sender or receiver is different in the two ways.

 
Input
First line, number of test cases, T.

Following are T test cases.

For each test case, the first line is number of people, n. Following are n-1 lines. Each line contains two numbers.



Sum of all n <= 1000000.
 
Output
T lines, each line is answer to the corresponding test case. Since the answers may be very large, you should output them modulo 109+7.
 
Sample Input
2
2
1 2
3
1 2
2 3
 
Sample Output
2
6
 
Source
 
Recommend
zhuyuanchen520   |   We have carefully selected several similar problems for you:  5017 

pid=5016" target="_blank">5016 5015 

pid=5014" target="_blank">5014 5013 

 题意:
n个人,构成树形关系。每一个人有一条独一无二的信息。每一个人能够将自己的信息通过树边。共享给与他相邻的人,共享之后。被共享的人拥有他原有的信息和共享的来的信息。

每次共享为一次操作。问每一个人都拥有全部人的信息最小要的次数的共享方法有多少种。

思路:
easy的出。最短的时间内。当然是每一个节点将自己的信息想外传出去一次。而且接受一次信息,也就是树边的2倍2*(n-1)。

然后能够证明。在最短时间内,全部的传递方式都有一个“信息转换点”——其它节点的信息首先传递到此节点,然后信息再从这个节点向其它节点传递。

事实上我们要求的就是拓扑序有多少种。定义dp[u]表示u节点下面。传到u节点的拓扑序有多少种,cnt[u]表示u有多少个子孙节点,f[i] = i!(i的阶乘)。c[i][j]表示组合数。

如果它有v1,v2,v3个节点。它们的拓扑序分别有dp[v1],dp[v2],dp[v3]这么多种。

那么dp[u] = c[cnt[u]-1][cnt[v1]] * c[cnt[u]-1-cnt[v1]][cnt[v2]]
* c[cnt[u]-1-cnt[v1]-cnt[v2]][cnt[v3]] * dp[v1] * dp[v2] * dp[v3](这个自己推推吧)。化简以后。得到dp[u] = f[cnt[u]-1] / ( f[cnt[v1]] * f[cnt[v2]] * f[cnt[v3]] ) * dp[v1] * dp[v2] * dp[v3] 。我们能够在o(n)的时间复杂度内算出以1节点为根的全部dp值(那么以1为根的答案就算出来了)。以及其它一些辅助信息的值。然后按树的结构往下遍历。分别计算以其它节点为根的答案。以上是网上的思路。我想说的是自己的一点理解。为什么知道每一个子树的拓扑序数目。就能够退出自己的拓扑序数目呢。事实上非常好理解的。当每一个子树的拓扑序定下来之后。确定总顺序的时候。

也就是要得到一个长度为cnt[u]拓扑序列。

对于子树i。

也有一个长度为cnt[i]拓扑序列,所以就要在cnt[u]里找cnt[i]个位置。其它子树再在剩下的子树里找。

还有换根的时候该怎么推导。先写出

dp[u]'=dp[u]*(n-sz[v]-1)!*sz[v]!/((n-1)!*dp[v])
dp[v]'=dp[v]*(n-1)!*dp[u]'/((sz[v]-1)!*(n-sz[v])!)。

带入dp[u]'就能够约掉非常多东西了。所以推公式的时候不要急着得到最后答案。还有就是为什么答案数就是拓扑序数的平方。

由于信息传回去的时候就是你拓扑序嘛。和拓扑序数目一样的。

每个正拓扑序能够和一个逆拓扑序组合。所以就有平方种啦。

具体见代码:
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000010;
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long ll;
const ll mod=1e9+7;
ll fac[maxn],dp[maxn],ans;
int cnt,sz[maxn],n;
struct node
{
int v;
node *next;
} ed[maxn<<1],*head[maxn];
void adde(int u,int v)
{
ed[cnt].v=v;
ed[cnt].next=head[u];
head[u]=&ed[cnt++];
}
ll pow_mod(ll x,int k)
{
ll base=x,ret=1;
while(k)
{
if(k&1)
ret=(ret*base)%mod;
base=(base*base)%mod;
k>>=1;
}
return ret;
}
ll ni(ll x){ return pow_mod(x,mod-2); }
void dfs(int fa,int u)
{
ll tp;
dp[u]=tp=sz[u]=1;
for(node *p=head[u];p!=NULL;p=p->next)
{
int v=p->v;
if(v==fa)
continue;
dfs(u,v);
tp=(tp*ni(fac[sz[v]]))%mod;
dp[u]=(dp[u]*dp[v])%mod;
sz[u]+=sz[v];
}
dp[u]=(dp[u]*fac[sz[u]-1]%mod*tp)%mod;
}
void solve(int fa,int u,ll tp)
{
ll tt;
ans=(ans+tp*tp%mod)%mod;
for(node *p=head[u];p!=NULL;p=p->next)
{
int v=p->v;
if(v==fa)
continue;
tt=(tp*fac[n-sz[v]-1]%mod*fac[sz[v]])%mod;
tt=(tt*ni(fac[sz[v]-1])%mod*ni(fac[n-sz[v]]))%mod;
solve(u,v,tt);
}
}
int main()
{
int t,i,u,v,rt; fac[0]=fac[1]=1;
for(i=2;i<maxn;i++)
fac[i]=(i*fac[i-1])%mod;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
cnt=0,ans=0;
for(i=1;i<=n;i++)
head[i]=NULL;
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
adde(u,v);
adde(v,u);
}
rt=(n+1)/2;
dfs(-1,rt);
solve(-1,rt,dp[rt]);
printf("%I64d\n",ans);
}
return 0;
}


版权声明:本文博主原创文章,博客,未经同意不得转载。

hdu 4661 Message Passing(木DP&amp;组合数学)的更多相关文章

  1. HDU 4661 Message Passing ( 树DP + 推公式 )

    参考了: http://www.cnblogs.com/zhsl/archive/2013/08/10/3250755.html http://blog.csdn.net/chaobaimingtia ...

  2. HDU 4661 Message Passing 【Tree】

    题意: 给一棵树,每一个结点都有一个信息,每一个时刻,某一对相邻的结点之间可以传递信息,那么存在一个最少的时间,使得所有的节点都可以拥有所有的信息.但是,题目不是求最短时间,而是求最短时间的情况下,有 ...

  3. HDU-4661 Message Passing 树形DP,排列组合

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661 题意:有n个人呈树状结构,每个人知道一个独特的消息.每次可以让一个人将他所知的所有消息告诉和他相 ...

  4. HDU 1003 Max Sum --- 经典DP

    HDU 1003    相关链接   HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...

  5. hdu 5094 Maze 状态压缩dp+广搜

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092176.html 题目链接:hdu 5094 Maze 状态压缩dp+广搜 使用广度优先 ...

  6. hdu 2829 Lawrence(斜率优化DP)

    题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...

  7. hdu 4568 Hunter 最短路+dp

    Hunter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  8. HDU 1231.最大连续子序列-dp+位置标记

    最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  9. HDU 1078 FatMouse and Cheese ( DP, DFS)

    HDU 1078 FatMouse and Cheese ( DP, DFS) 题目大意 给定一个 n * n 的矩阵, 矩阵的每个格子里都有一个值. 每次水平或垂直可以走 [1, k] 步, 从 ( ...

随机推荐

  1. Python 实现的下载op海贼王网的图片(网络爬虫)

    没得事就爬一下我喜欢的海贼王上的图片 须要在d盘下建立一个imgcache目录 # -*- coding: utf-8 -*- import urllib import urllib2 import ...

  2. IBM之MQ使用指南

    随着计算机网络和分布式应用的不断发展.远程消息传递越来越成为应用系统中必不可少的组成部分. 商业消息中间件的出现保证了消息传输的可靠性,高效率和安全性,同一时候也降低了系统的开发周期. 眼下应用最多的 ...

  3. HDU1300DP

    /* HDU1300 DP 特定n饰品种类 每个饰品的两个数据.amount[i]代表数量.price[i]代表单位价格 购买珠宝时要满足下面购买规则: 单独买:每种珠宝要加上数量10 合并买:能够把 ...

  4. android-包签名

    android-包签名 应用能在Android 系统上安装必须是经过有私有key的证书数据签名.Android系统通过证书确定应用的作者,和与应用建立信任关系.证书不会用于控制应用的安装.证书不需要权 ...

  5. OpenCV-Python教程(5、初级滤波内容)

    本篇文章介绍如何用OpenCV-Python来实现初级滤波功能. 提示: 转载请详细注明原作者及出处,谢谢! 本文介绍使用OpenCV-Python实现基本的滤波处理 本文不介绍滤波处理的详细概念,所 ...

  6. unity中的MonoBehaviour.OnMouseDown()

    在官网的api文档中仅说明了 Description OnMouseDown is called when the user has pressed the mouse button while ov ...

  7. onmouseover 执行 ToolTip 控件

    Tooltip控件是一个简单,但非常有用的控件.它能够为我们的软件提供非常漂亮的提示信息,提高软件的可用性,给用户比较好的体验.假设现在有两个按钮,一个用来预览吊线世系图,一个用来预览行转.为了保持按 ...

  8. windows phone (14) 简单了解Ellipse元素和Rectangle元素

    原文:windows phone (14) 简单了解Ellipse元素和Rectangle元素  System.Windows.Shapes命名空间中包含了显示矢量图形的元素分别为ellipse和re ...

  9. windows phone 独立存储空间的操作 (2)

    原文:windows phone 独立存储空间的操作 (2) IsolatedStorage独立存储空间是保存应用程序的一些数据已经配置文件,独立存储空间相对于其他的wp程序是独立的,也就是说每个wp ...

  10. 【Cocos2d-x 粒子系统】火球用手指飞起来

    程序: 创建球 sp1 = CCSprite::create("ball.png"); sp1->setPosition(ccp(10, visibleSize.height ...