Codeforces 1060 F. Shrinking Tree

Source: Internet
Author: User

Topic links

A good problem of thinking ah ... Feel this type of question is very test basic skills are solid (like me to hang up).

Test instructions: You have a tree of \ (n\) , each randomly select an edge, the edge of the two endpoints merge, and randomly inherit one of the two point labels, ask for each point, the final remaining point marking equals its label probability. \ (N\leq 50\), output by floating-point number.

Hit the floating point output of the problem is very afraid of the card, but this problem seems to be not card, worried that the card can open \ (long \ double\)(also to spit a word CF's \ (c++11\) to \ (long\ double\) The output seems to be not very porcelain ... Also go to \ (double\) output).

Okay, now let's start with the practice. Our general idea is to solve each point separately . For each point, a method is used to figure out the number of solutions it will eventually leave, then dividing by \ ((n-1)!\) is clearly the answer. However, it is important to note that the inheritance of the label is random, so for the same kind of deletion order, the result may be different, so we figure out that the point in all order to retain the sum of the probability (may be a floating point), but in order to express the simplicity of the next, may not be rigorous call it a program number.

Now to care about how to find the number of scenarios left at each point, we will ask for the point \ (x\) of the answer to be the root of the tree, and \ (size_i\) to represent the size of the subtree with \ (i\) as the root. Consider the tree \ (dp\), we use \ (f_{i,j}\) to indicate when the label of the root node inherits to the \ (i\) point, if \ (i\) subtree is left \ (j\) Edge , the number of scenarios in which the label of the root node is ultimately retained. Then \ (f_{x,n-1}\) is the answer we want.

Let's tackle a small problem first:

Suppose we divide the subtree of the current node \ (u\) into two parts, and we already know the number of scenarios ( a\) and the right half ( j\) of the left half remaining \ (i\) edges. The number of scenarios at the Edge (b\), how to solve their contribution to the number of subtrees (i+j\) edges of the whole tree?

Obviously the left and right two parts of the subtree have no effect on each other, so we can combine the options. As long as the remaining left side \ (i\) and the right side of the \ (j\) are deleted after the relative order is not changed, then the same result must be obtained, so this part of the combined scheme is \ ({{i+j}\choose i}\) (that is, the \ (i+j\) space of the delete sequence ( i\) to the left edge).

We also have to pay attention to the deleted edges, which also need to be combined in a real sequence of operations. Therefore, similar to the above, we assume that there is a total of \ (x\) on the left side, the right side originally has a \ (y\) Edge, then this part of the combined scheme is \ ({{x+y-i-j}\choose x-i}\).

In summary, their contribution should be \ (a*b*{{i+j}\choose i}*{{x+y-i-j}\choose x-i}\).

Then continue thinking along the way, we may be able to take the following strategy \ (dp\): For a tree with \ (u\) root, regardless of any subtree, there is \ (f_{u,0}=1\). If we had a way to calculate the answer to a single point when we were considering only one subtrees tree, then our problem would be done, because when we consider a subtrees tree, we can calculate the answer to consider it as we just said "right half", and think of the previously calculated part as " The left half ", you can merge directly according to the previous method.

Now all we have to do is figure out how to calculate the answer to a subtrees tree only considering \ (u\) , set its root to \ (v\). Obviously we can enumerate \ (i\), which means we want to ask for an answer to the i\ Bar, set it to \ (g_i\), then enumerate \ (j\), consider \ (F_{v,j} \) contribution to \ (g_i\) . In two categories of case discussion:

\ (1\) , assuming \ (j<i\) , obviously the legal process should look like this: \ (v\) is merged into the remaining \ (i-1\) Edge, the label of the root inherits from the \ (u\) , and then \ (v\) , the edges in the subtree continue to merge into only the remaining \ (j\) bar, followed by the label of the root from \ (u\) to the \ (v\) . Note that the probability of \ (u\) is inherited to \ (v\) . \ (\frac{1}{2}\) , so at this time \ (f_{v,j}\) to \ (g_i\) is \ (\frac{1}{2}f_{v,j}\) .

\ (2\) , assuming \ (j=i\) , obviously the legal process should be like this: \ (v\) originally had \ (size_v-1\) edge, if left \ (i\) bar, you should remove \ (size_v-1-i\) edge, and \ (u\) to \ (v\) should also be deleted along with the deletion of those edges, considering the deleted \ (size_v-1-i\) bars, \ (u\) to \ (v\) can be inserted into \ (size_v-i\) Any one of the empty spaces (because both ends are also available). At the same time we can see that when the label of the root node is inherited to the \ (u\) , \ (u\) and \ (v\) has disappeared, so there is no need to consider the probability of \ (\frac{1}{2}\) , and the contribution is \ ((size_v-i) *f_{v,j}\) .

\ (3\), hypothesis \ (j>i\), paint to consider that this is not a legitimate solution, the contribution is \ (0\).

So we finally finished the last piece of the puzzle and got a workable solution. Finally, summing up the practice, we calculate each answer separately, followed by the tree (dp\). For every new son we consider, we first calculate the case of this subtree and then merge it with the original answer. A rough calculation of the complexity of each point to update its contribution to the father at most is \ (o (n^2) \) , so the calculation of a point of the complexity of the answer is \ (o (n^3) \), the calculation of all points is \ (o (n^4) \) Of Because it is rough calculation so the upper bound is actually very loose, the constant is relatively small, so it can be passed.

My Code:

#include <cstdio> #include <vector>using std::vector;typedef long double ldb;const int n=55;int n;vector< int> g[n];int size[n];ldb fact[n];ldb dp[n][n],tmp[n],g[n];inline ldb choose (int n,int m) {return fact[n]/(fact[m]*f ACT[N-M]);}    void Dfs (int now,int father) {Register int i,j;    Dp[now][0]=1;size[now]=1;        for (auto X:g[now]) {if (x==father) continue;        DFS (X,now);            for (i=0;i<=size[x];i++) {g[i]=0;                for (j=1;j<=size[x];j++) if (j<=i) g[i]+=0.5*dp[x][j-1];        else G[i]+=dp[x][i];        } for (i=0;i<size[now]+size[x];i++) tmp[i]=0; for (i=0;i<size[now];i++) for (j=0;j<=size[x];j++) tmp[i+j]+=dp[now][i]*g[j]*choose (i+j,i) *c        Hoose (size[now]-1-i+size[x]-j,size[now]-1-i);        for (i=0;i<size[now]+size[x];i++) dp[now][i]=tmp[i];    SIZE[NOW]+=SIZE[X]; } RETUrn;}    Signed main () {int x, y;    register int i;    scanf ("%d", &n);    Fact[0]=1;    for (i=1;i<=n-1;i++) fact[i]=fact[i-1]*i;        for (i=1;i<=n-1;i++) {scanf ("%d%d", &x,&y);        G[x].push_back (y);    G[y].push_back (x);        } for (i=1;i<=n;i++) {DFS (i,0);    printf ("%.9lf\n", (double) (dp[i][n-1]/fact[n-1])); } return 0;}

Codeforces 1060 F. Shrinking Tree

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.