Randomization?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 297 Accepted Submission(s): 171
Problem Description
Random is the real life. What we see and sense everyday are absolutely randomly happened. Randomization is the process of making something random, as the nature.
Given a tree with N nodes, to be more precisely, a tree is a graph in which each pair of nodes has and only has one path. All of the edges’ length is a random integer lies in interval [0, L] with equal probability. iSea want to know the probability to form a tree, whose edges’ length are randomly generated in the given interval, and in which the path's length of every two nodes does not exceed S.
Given a tree with N nodes, to be more precisely, a tree is a graph in which each pair of nodes has and only has one path. All of the edges’ length is a random integer lies in interval [0, L] with equal probability. iSea want to know the probability to form a tree, whose edges’ length are randomly generated in the given interval, and in which the path's length of every two nodes does not exceed S.
Input
The first line contains a single integer T, indicating the number of test cases.
Each test case includes three integers N, L, S. Then N - 1 lines following, each line contains two integers Ai and Bi, describing an edge of the tree.
Technical Specification
1. 1 <= T <= 512
2. 1 <= N <= 64
3. 1 <= L <= 8, 1 <= S <= 512
4. 1 <= Ai, Bi <= N
Each test case includes three integers N, L, S. Then N - 1 lines following, each line contains two integers Ai and Bi, describing an edge of the tree.
Technical Specification
1. 1 <= T <= 512
2. 1 <= N <= 64
3. 1 <= L <= 8, 1 <= S <= 512
4. 1 <= Ai, Bi <= N
Output
For each test case, output the case number first, then the probability rounded to six fractional digits.
Sample Input
3 2 3 2 1 2 4 3 4 1 2 2 3 3 4 7 4 10 1 2 2 3 4 5 2 6 4 7 4 6
Sample Output
Case 1: 0.750000 Case 2: 0.500000 Case 3: 0.624832
Author
iSea@WHU
Source
树型Dp都好难呀、
题目大意:
给你N个点构成的一棵树。每条边的权值可以设定为【0,L】区间内的任意一个价值,问任意两点间距离都不超过S的设定方案的概率。
思路:
思路参考自网络代码,看懂好难呀。
①设定Dp【u】【len】表示从节点u到以节点u为根的子树中的所有点的最大距离是len的概率,并且需要奥正其子树节点中两两距离不超过S。
②那么考虑两两子节点进行合并(哇第一次见这种骚操作。)
③设定Dist【i】表示当前子节点v的子树中,距离节点u的最远距离为i的概率。
那么有:Dist【k+j】+=dp【v】【k】*(1/(L+1))这里j是枚举的从节点v到节点u这条路径上的长度。
④再设定temp【i】表示合并完当前节点v之后的dp【u】【i】的答案。
那么有:temp【max(j,k)】+=dp【u】【k】*Dist【j】;这里需要同时保证j+k<=S;
接下来每次合并结束之后,将dp【u】【i】更新为temp【i】,然后考虑合并下一个子节点v.
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int>mp[150];
double dp[65][515];
int n,L,S;
double mm;
double Dist[525];
double temp[525];
void Dfs(int u,int from)
{
mm=1;
mm/=(double)(L+1);
for(int i=0; i<=S; i++)dp[u][i]=0;
dp[u][0]=1;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(v==from)continue;
else
{
Dfs(v,u);
for(int j=0;j<=S;j++)
{
Dist[j]=temp[j]=0;
}
for(int j=0;j<=L;j++)
{
for(int k=0;k<=S;k++)
{
if(j+k<=S)
Dist[j+k]+=mm*dp[v][k];
}
}
for(int j=0;j<=S;j++)
{
for(int k=0;k<=S-j;k++)
{
temp[max(j,k)]+=dp[u][k]*Dist[j];
}
}
for(int j=0;j<=S;j++)dp[u][j]=temp[j];
}
}
}
int main()
{
int t;
int kase=0;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
scanf("%d%d%d",&n,&L,&S);
for(int i=1; i<=n; i++)mp[i].clear();
for(int i=0; i<n-1; i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
Dfs(1,-1);
double output=0;
for(int i=0; i<=S; i++)
{
output+=dp[1][i];
}
printf("Case %d: %.6f\n",++kase,output);
}
}