SRM540-div1-2-RandomColoring
2012-04-13 22:36
375 查看
zz:
http://www.strongczq.com/2012/04/srm540-div1-2-randomcoloring.html
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11840&rd=14732
[align=left]
[/align]
[align=left]题目大意:[/align]
[align=left] N个栅栏按照标号0,1,...,N-1围成一个圈,从0号栅栏开始染色。每一种颜色用(R,G,B)三原色表示,并且0<=R<maxR, 0<=G<maxG, 0<=B<maxB。规定相邻的两个栅栏颜色必须符合以下的颜色过渡条件:[/align]
两种颜色的对应R,G,B差值全部都小于等于d2
两种颜色的对应R,G,B差值至少有一个大于等于d1
[align=left]将0号栅栏染色为(startR, startG, startB), 然后按编号逐一染色,每次选择颜色时都是考虑前一个栅栏的颜色,随机等概率从所有符合过渡条件的颜色中挑选。问当完成N-1号栅栏的染色时,N-1与0之间不符合颜色过渡条件的概率是多少。[/align]
[align=left] 数据规模:N为[2,40], maxR,maxG,maxB均为[1,50], d1, d2均为[0, 50][/align]
[align=left]
[/align]
[align=left]思路:[/align]
[align=left] 这道题比较明显可以看出来是一道动态规划题,按照序号每次考虑一个栅栏被染成所有可能颜色的概率,状态变量为三原色取值r、g、b,一直计算到N-1栅栏,然后将不符合与0栅栏之间颜色过渡条件的那些颜色的概率相加即可。[/align]
[align=left] 从上面的分析看,动态规划的思路非常清晰,但是这道题的难点在于如何高效的实现状态间的转移。[/align]
[align=left] 用double[][][] dp表示当前栅栏所有颜色取值的概率值,double[][][] next表示下一个栅栏所有颜色取值的概率值。把每一种颜色的三原色(r,g,b)看作是三维空间中的一个点。对于当前栅栏的任意一种颜色(r,g,b),其概率值dp[r][g]将会均匀分配到next中符合过渡条件的那些颜色上,这个过程可以看作是颜色(r,g,b)概率值扩散的一个过程。对于颜色(r,g,b)而言,其概率所能扩散的范围受过渡条件限制,与当前的状态无关,我们用rSize[r][g][b]表示其所能扩散的范围,那么每一个扩散出来的点拥有dp[r][g][b]/rSize[r][g][b]的概率值(称为扩散概率值)。如果正向的累加next中每一种颜色的取值,那么计算复杂度为O(maxR*maxG*maxB)种当前颜色乘以O(maxR*maxG*maxB)种下一栅栏颜色,显然无法满足题目给定的数据规模要求。[/align]
[align=left] 我们需要从反向考虑问题,考虑下一栅栏的每一种(r,g,b)颜色的概率值next[r][g][b]由当前栅栏的哪些颜色的概率扩散形成。对于颜色(r,g,b),根据颜色过渡条件,其所有扩散源颜色在三维空间中可以表示成一个边长为(2*d2+1)的立方体,中间挖去边长为(2*d1-1)的立方体。显然,我们不可能把所有扩散源的扩散概率值累加起来,这样不会降低计算的复杂度。优化方案为对这些扩散概率值进行预处理,令sum[r+1][g+1][b+1]表示当前栅栏颜色空间中由(0,0,0)和(r,g,b)所表示的长方体内所有扩散概率值的加和,计算这样的sum数组只需要O(maxR*maxG*maxB)复杂度。根据sum数组,可以O(1)复杂度计算出三维空间中所有立方体的扩散概率值累加和,所以每一个next[r][g][b]计算复杂度都是O(1)。因此,每一个栅栏的颜色空间概率计算包含了两个O(maxR*maxG*maxB)的过程。所有N个栅栏的总时间复杂度为O(N*maxR*maxG*maxB),符合题目数据规模要求。[/align]
[align=left]
[/align]
[align=left]
[/align]
[align=left][b]Java代码:[/align]
http://www.strongczq.com/2012/04/srm540-div1-2-randomcoloring.html
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11840&rd=14732
[align=left]
[/align]
[align=left]题目大意:[/align]
[align=left] N个栅栏按照标号0,1,...,N-1围成一个圈,从0号栅栏开始染色。每一种颜色用(R,G,B)三原色表示,并且0<=R<maxR, 0<=G<maxG, 0<=B<maxB。规定相邻的两个栅栏颜色必须符合以下的颜色过渡条件:[/align]
两种颜色的对应R,G,B差值全部都小于等于d2
两种颜色的对应R,G,B差值至少有一个大于等于d1
[align=left]将0号栅栏染色为(startR, startG, startB), 然后按编号逐一染色,每次选择颜色时都是考虑前一个栅栏的颜色,随机等概率从所有符合过渡条件的颜色中挑选。问当完成N-1号栅栏的染色时,N-1与0之间不符合颜色过渡条件的概率是多少。[/align]
[align=left] 数据规模:N为[2,40], maxR,maxG,maxB均为[1,50], d1, d2均为[0, 50][/align]
[align=left]
[/align]
[align=left]思路:[/align]
[align=left] 这道题比较明显可以看出来是一道动态规划题,按照序号每次考虑一个栅栏被染成所有可能颜色的概率,状态变量为三原色取值r、g、b,一直计算到N-1栅栏,然后将不符合与0栅栏之间颜色过渡条件的那些颜色的概率相加即可。[/align]
[align=left] 从上面的分析看,动态规划的思路非常清晰,但是这道题的难点在于如何高效的实现状态间的转移。[/align]
[align=left] 用double[][][] dp表示当前栅栏所有颜色取值的概率值,double[][][] next表示下一个栅栏所有颜色取值的概率值。把每一种颜色的三原色(r,g,b)看作是三维空间中的一个点。对于当前栅栏的任意一种颜色(r,g,b),其概率值dp[r][g]将会均匀分配到next中符合过渡条件的那些颜色上,这个过程可以看作是颜色(r,g,b)概率值扩散的一个过程。对于颜色(r,g,b)而言,其概率所能扩散的范围受过渡条件限制,与当前的状态无关,我们用rSize[r][g][b]表示其所能扩散的范围,那么每一个扩散出来的点拥有dp[r][g][b]/rSize[r][g][b]的概率值(称为扩散概率值)。如果正向的累加next中每一种颜色的取值,那么计算复杂度为O(maxR*maxG*maxB)种当前颜色乘以O(maxR*maxG*maxB)种下一栅栏颜色,显然无法满足题目给定的数据规模要求。[/align]
[align=left] 我们需要从反向考虑问题,考虑下一栅栏的每一种(r,g,b)颜色的概率值next[r][g][b]由当前栅栏的哪些颜色的概率扩散形成。对于颜色(r,g,b),根据颜色过渡条件,其所有扩散源颜色在三维空间中可以表示成一个边长为(2*d2+1)的立方体,中间挖去边长为(2*d1-1)的立方体。显然,我们不可能把所有扩散源的扩散概率值累加起来,这样不会降低计算的复杂度。优化方案为对这些扩散概率值进行预处理,令sum[r+1][g+1][b+1]表示当前栅栏颜色空间中由(0,0,0)和(r,g,b)所表示的长方体内所有扩散概率值的加和,计算这样的sum数组只需要O(maxR*maxG*maxB)复杂度。根据sum数组,可以O(1)复杂度计算出三维空间中所有立方体的扩散概率值累加和,所以每一个next[r][g][b]计算复杂度都是O(1)。因此,每一个栅栏的颜色空间概率计算包含了两个O(maxR*maxG*maxB)的过程。所有N个栅栏的总时间复杂度为O(N*maxR*maxG*maxB),符合题目数据规模要求。[/align]
[align=left]
[/align]
[align=left]
[/align]
[align=left][b]Java代码:[/align]
public class RandomColoring { int mR, mG, mB; private int calcSize(int r0, int g0, int b0, int r1, int g1, int b1) { r0 = Math. max(r0, 0); g0 = Math. max(g0, 0); b0 = Math. max(b0, 0); r1 = Math. min(r1, mR - 1); g1 = Math. min(g1, mG - 1); b1 = Math. min(b1, mB - 1); return (r1 - r0 + 1) * (g1 - g0 + 1) * (b1 - b0 + 1); } private double calcPropSum(int r0, int g0, int b0, int r1, int g1, int b1, double [][][] sum) { r0 = Math. max(r0, 0); g0 = Math. max(g0, 0); b0 = Math. max(b0, 0); r1 = Math. min(r1, mR - 1); g1 = Math. min(g1, mG - 1); b1 = Math. min(b1, mB - 1); return sum[r1 + 1][g1 + 1][b1 + 1] - sum[r0][g1 + 1][b1 + 1] - sum[r1 + 1][g0][b1 + 1] - sum[r1 + 1][g1 + 1][b0] + sum[r0][g0][b1 + 1] + sum[r0][g1 + 1][b0] + sum[r1 + 1][g0][b0] - sum[r0][g0][b0]; } public double getProbability(int N, int maxR, int maxG, int maxB, int startR, int startG, int startB, int d1, int d2) { mR = maxR; mG = maxG; mB = maxB; int[][][] rSize = new int[ mR][ mG][ mB]; for (int r = 0; r < mR; ++r) { for (int g = 0; g < mG; ++g) { for (int b = 0; b < mB; ++b) { rSize[r][g][b] = calcSize(r - d2, g - d2, b - d2, r + d2, g + d2, b + d2); if (d1 > 0) { rSize[r][g][b] -= calcSize(r - d1 + 1, g - d1 + 1, b - d1 + 1, r + d1 - 1, g + d1 - 1, b + d1 - 1); } } } } double[][][] dp = new double[ mR][ mG][ mB]; dp[startR] 7631 [startG][startB] = 1.0; double[][][] sum = new double[ mR + 1][ mG + 1][ mB + 1]; for (int i = 0; i < N - 1; ++i) { double[][][] next = new double[ mR][ mG][ mB]; for (int r = 0; r < mR; ++r) { for (int g = 0; g < mG; ++g) { for (int b = 0; b < mB; ++b) { sum[r + 1][g + 1][b + 1] = sum[r][g + 1][b + 1] + sum[r + 1][g][b + 1] + sum[r + 1][g + 1][b] - sum[r][g][b + 1] - sum[r + 1][g][b] - sum[r][g + 1][b] + sum[r][g][b]; if (dp[r][g][b] > 0.0 && rSize[r][g][b] > 0) { sum[r + 1][g + 1][b + 1] += dp[r][g][b] / rSize[r][g][b]; } } } } for (int r = 0; r < mR; ++r) { for (int g = 0; g < mG; ++g) { for (int b = 0; b < mB; ++b) { next[r][g][b] = calcPropSum(r - d2, g - d2, b - d2, r + d2, g + d2, b + d2, sum); if (d1 > 0) { next[r][g][b] -= calcPropSum(r - d1 + 1, g - d1 + 1, b - d1 + 1, r + d1 - 1, g + d1 - 1, b + d1 - 1, sum); } } } } dp = next; } double res = 0; for (int r = 0; r < mR; ++r) { for (int g = 0; g < mG; ++g) { for (int b = 0; b < mB; ++b) { if (Math.abs(r - startR) <= d2 && Math. abs(g - startG) <= d2 && Math. abs(b - startB) <= d2) { if (Math.abs(r - startR) >= d1 || Math. abs(g - startG) >= d1 || Math. abs(b - startB) >= d1) { res += dp[r][g][b]; } } } } } return 1 - res; } }
相关文章推荐
- TC SRM 540 DIV2
- [拉格朗日插值]SRM 683 Div1 Hard RandomWalkOnGrid
- SRM540-div1-1-div2-2-ImportantSequence
- SRM540-div2-3-FractionInDifferentBases
- srm540 div1
- Topcoder SRM 656 (Div.1) 250 RandomPancakeStack - 概率+记忆化搜索
- Codeforces Round #247(Div. 2) D. Random Task 二分+前缀和
- SRM 452 div1(practice)
- SRM 588 DIV1
- topcoder srm 360 div1
- topcoder srm 600 div1
- Topcoder SRM 664 DIV 1
- Topcoder SRM 413 (Div 2) 1000.InfiniteSequence
- TC SRM 570 div2 1000【Tree,树上统计】
- N排列盒子涂色方法总和 DP SRM 666 div1 medium SumOverPermutations
- Topcoder SRM 663 DIV 1
- TopCoder算法竞赛题2:SRM 146 DIV 2, 250-point
- TopCoder算法竞赛题5:SRM 149 DIV 2, 250-point
- SRM574 Div1 450
- SRM556 Div1 555