您的位置:首页 > 编程语言 > Java开发

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]
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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  class java 优化