coreBugZJ

此 blog 已弃。

EOJ 1096 棋盘分割 (动态规划)

  1/*
  2EOJ 1096 棋盘分割
  3
  4
  5----题目描述:
  6
  7将一个 8*8 的棋盘进行如下分割:
  8将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下部分继续如此分割,
  9这样割了 n-1 次后,连同最后剩下的矩形棋盘共有 n 块矩形棋盘。
 10每次切割都只能沿着棋盘格子的边进行。
 11
 12原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。
 13现需要把棋盘按上述规则分割成 n 块矩形棋盘,并使各矩形棋盘总分的均方差最小。
 14
 15均方差 O'    = sqrt( sigma((x[i]-avgX) * (x[i]-avgX)) / n );
 16平均值 avgX  = sigma(x[i]) / n;
 17其中  x[i] 为第 i 块矩形棋盘的分。
 18
 19
 20请编程对给出的棋盘及 n,求出 O' 的最小值。
 21
 22----输入:
 23
 24第 1 行为一个整数n(1 <= n <= 15 );
 25第 2 行至第 9 行每行为 8 个小于 100 的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
 26
 27
 28----输出:
 29
 30仅一个数,为O'(四舍五入精确到小数点后三位)。
 31
 32----样例输入:
 33
 343
 351 1 1 1 1 1 1 3
 361 1 1 1 1 1 1 1
 371 1 1 1 1 1 1 1
 381 1 1 1 1 1 1 1
 391 1 1 1 1 1 1 1
 401 1 1 1 1 1 1 1
 411 1 1 1 1 1 1 0
 421 1 1 1 1 1 0 3
 43
 44----样例输出:
 45
 461.633
 47
 48
 49----分析:
 50
 51对给定棋盘和 n,
 52可以确定 avgX,
 53而为了确定 O',可以穷举所有可能的切割方案,从而找到最小值,
 54具体实现为 记忆化搜索,或者动态规划,以减少冗余计算。
 55
 56具体见代码注释。
 57*/

 58
 59
 60
 61/*************************************************************
 62版本四
 63实现同版本三,
 64修改之处为,
 65部分数组由 double 改为 int 且去掉了一个数组 a[][] 。
 66
 67具体见代码。
 68*/

 69/*
 70#include <stdio.h>
 71#include <math.h>
 72
 73#define  L     9
 74#define  N     16
 75#define  INF   1e150
 76
 77int    n, s[ L ][ L ];
 78double avgX, f[ L ][ L ][ L ][ L ][ N ];
 79
 80void init() {
 81        int i, j, u, v, k;
 82        for ( i = 0; i < L; ++i ) {
 83                s[ 0 ][ i ] = s[ i ][ 0 ] = 0;
 84        }
 85        for ( i = 1; i < L; ++i ) {
 86                for ( j = 1; j < L; ++j ) {
 87                        s[ i ][ j ] = s[ i-1 ][ j ] + s[ i ][ j-1 ] - s[ i-1 ][ j-1 ] + s[ i ][ j ];
 88                }
 89        }
 90        for ( i = 0; i < L; ++i ) {
 91                for ( j = 0; j < L; ++j ) {
 92                        for ( u = 0; u < L; ++u ) {
 93                                for ( v = 0; v < L; ++v ) {
 94                                        for ( k = 0; k < N; ++k ) {
 95                                                f[i][j][u][v][k] = INF * 3;
 96                                        }
 97                                }
 98                        }
 99                }
100        }
101        avgX = ((double)(s[ L-1 ][ L-1 ])) / n;
102}
103
104double solve( int i, int j, int u, int v, int m ) {
105        double tmp, tf;
106        int    p;
107
108        if ( INF * 2 > f[i][j][u][v][m] ) {
109                return f[i][j][u][v][m];
110        }
111
112        if ( 0 == m ) {
113                tmp = s[u][v] - s[i-1][v] - s[u][j-1] + s[i-1][j-1] - avgX;
114                return ( f[i][j][u][v][m] = tmp * tmp );
115        }
116        tf = INF;
117        for ( p = j; p < v; ++p ) {
118                tmp = solve(i,j,u,p,0) + solve(i,p+1,u,v,m-1);
119                if ( tmp < tf ) {
120                        tf = tmp;
121                }
122                tmp = solve(i,j,u,p,m-1) + solve(i,p+1,u,v,0);
123                if ( tmp < tf ) {
124                        tf = tmp;
125                }
126        }
127        for ( p = i; p < u; ++p ) {
128                tmp = solve(i,j,p,v,0) + solve(p+1,j,u,v,m-1);
129                if ( tmp < tf ) {
130                        tf = tmp;
131                }
132                tmp = solve(i,j,p,v,m-1) + solve(p+1,j,u,v,0);
133                if ( tmp < tf ) {
134                        tf = tmp;
135                }
136        }
137        return ( f[i][j][u][v][m] = tf );
138}
139
140int main() {
141        int i, j;
142        double ans;
143        scanf( "%d", &n );
144        for ( i = 1; i < L; ++i ) {
145                for ( j = 1; j < L; ++j ) {
146                        scanf( "%d", &s[i][j] );
147                }
148        }
149        init();
150        ans = sqrt( solve(1, 1, L-1, L-1, n-1) / n );
151        printf( "%0.3lf\n", ans );
152        return 0;
153}
154*/

155
156
157/*************************************************************
158版本三
159思路同版本二,记忆化搜索,
160修改之处为,
161对于无解的情况也要记忆,而版本二中忽略了这一点。
162
163具体见代码。
164*/

165/*
166#include <stdio.h>
167#include <math.h>
168
169#define  L     9
170#define  N     16
171#define  INF   1e150
172
173int n;
174double  avgX, a[ L ][ L ], s[ L ][ L ], f[ L ][ L ][ L ][ L ][ N ];
175
176void init() {
177        int i, j, u, v, k;
178        for ( i = 0; i < L; ++i ) {
179                s[ 0 ][ i ] = s[ i ][ 0 ] = 0;
180        }
181        for ( i = 1; i < L; ++i ) {
182                for ( j = 1; j < L; ++j ) {
183                        s[ i ][ j ] = s[ i-1 ][ j ] + s[ i ][ j-1 ] - s[ i-1 ][ j-1 ] + a[ i ][ j ];
184                }
185        }
186        for ( i = 0; i < L; ++i ) {
187                for ( j = 0; j < L; ++j ) {
188                        for ( u = 0; u < L; ++u ) {
189                                for ( v = 0; v < L; ++v ) {
190                                        for ( k = 0; k < N; ++k ) {
191                                                f[i][j][u][v][k] = INF * 3;
192                                        }
193                                }
194                        }
195                }
196        }
197        avgX = s[ L-1 ][ L-1 ] / n;
198}
199
200double solve( int i, int j, int u, int v, int m ) {
201        double tmp, tf;
202        int    p;
203
204        if ( INF * 2 > f[i][j][u][v][m] ) {
205                return f[i][j][u][v][m];
206        }
207
208        if ( 0 == m ) {
209                tmp = s[u][v] - s[i-1][v] - s[u][j-1] + s[i-1][j-1] - avgX;
210                return ( f[i][j][u][v][m] = tmp * tmp );
211        }
212        tf = INF;
213        for ( p = j; p < v; ++p ) {
214                tmp = solve(i,j,u,p,0) + solve(i,p+1,u,v,m-1);
215                if ( tmp < tf ) {
216                        tf = tmp;
217                }
218                tmp = solve(i,j,u,p,m-1) + solve(i,p+1,u,v,0);
219                if ( tmp < tf ) {
220                        tf = tmp;
221                }
222        }
223        for ( p = i; p < u; ++p ) {
224                tmp = solve(i,j,p,v,0) + solve(p+1,j,u,v,m-1);
225                if ( tmp < tf ) {
226                        tf = tmp;
227                }
228                tmp = solve(i,j,p,v,m-1) + solve(p+1,j,u,v,0);
229                if ( tmp < tf ) {
230                        tf = tmp;
231                }
232        }
233        return ( f[i][j][u][v][m] = tf );
234}
235
236int main() {
237        int i, j;
238        double ans;
239        scanf( "%d", &n );
240        for ( i = 1; i < L; ++i ) {
241                for ( j = 1; j < L; ++j ) {
242                        scanf( "%lf", &a[i][j] );
243                }
244        }
245        init();
246        ans = sqrt( solve(1, 1, L-1, L-1, n-1) / n );
247        printf( "%0.3lf\n", ans );
248        return 0;
249}
250*/

251
252
253/*************************************************************
254版本二(TLE)
255记忆化搜索。
256
257函数 double solve( int i, int j, int u, int v, int m ) 
258求解棋盘某局部切割 m 次所得到的最小 sigma((x[?]-avgX) * (x[?]-avgX)),
259其中 x[?] 为从此局部中切割出的某块矩形棋盘的分。
260
261计算过程实现为穷举本局部所有可行的切割方案,在穷举中递归计算子问题。
262
263计算后使用数组记录本次计算的结果,
264若再次计算相同的问题,则直接从数组中读出,而不必重新计算。
265
266具体见代码。
267*/

268/*
269#include <stdio.h>
270#include <math.h>
271
272#define  L     9
273#define  N     16
274#define  INF   1e150
275
276int n;
277double  avgX, a[ L ][ L ], s[ L ][ L ], f[ L ][ L ][ L ][ L ][ N ];
278
279void init() {
280        int i, j, u, v, k;
281        for ( i = 0; i < L; ++i ) {
282                s[ 0 ][ i ] = s[ i ][ 0 ] = 0;
283        }
284        for ( i = 1; i < L; ++i ) {
285                for ( j = 1; j < L; ++j ) {
286                        s[ i ][ j ] = s[ i-1 ][ j ] + s[ i ][ j-1 ] - s[ i-1 ][ j-1 ] + a[ i ][ j ];
287                }
288        }
289        for ( i = 0; i < L; ++i ) {
290                for ( j = 0; j < L; ++j ) {
291                        for ( u = 0; u < L; ++u ) {
292                                for ( v = 0; v < L; ++v ) {
293                                        for ( k = 0; k < N; ++k ) {
294                                                f[i][j][u][v][k] = INF + INF;
295                                        }
296                                }
297                        }
298                }
299        }
300        avgX = s[ L-1 ][ L-1 ] / n;
301}
302
303double solve( int i, int j, int u, int v, int m ) {
304        double tmp, tf;
305        int    p;
306
307        if ( INF > f[i][j][u][v][m] ) {
308                return f[i][j][u][v][m];
309        }
310
311        if ( 0 == m ) {
312                tmp = s[u][v] - s[i-1][v] - s[u][j-1] + s[i-1][j-1] - avgX;
313                return ( f[i][j][u][v][m] = tmp * tmp );
314        }
315        tf = INF + INF;
316        for ( p = j; p < v; ++p ) {
317                tmp = solve(i,j,u,p,0) + solve(i,p+1,u,v,m-1);
318                if ( tmp < tf ) {
319                        tf = tmp;
320                }
321                tmp = solve(i,j,u,p,m-1) + solve(i,p+1,u,v,0);
322                if ( tmp < tf ) {
323                        tf = tmp;
324                }
325        }
326        for ( p = i; p < u; ++p ) {
327                tmp = solve(i,j,p,v,0) + solve(p+1,j,u,v,m-1);
328                if ( tmp < tf ) {
329                        tf = tmp;
330                }
331                tmp = solve(i,j,p,v,m-1) + solve(p+1,j,u,v,0);
332                if ( tmp < tf ) {
333                        tf = tmp;
334                }
335        }
336        return ( f[i][j][u][v][m] = tf );
337}
338
339int main() {
340        int i, j;
341        double ans;
342        scanf( "%d", &n );
343        for ( i = 1; i < L; ++i ) {
344                for ( j = 1; j < L; ++j ) {
345                        scanf( "%lf", &a[i][j] );
346                }
347        }
348        init();
349        ans = sqrt( solve(1, 1, L-1, L-1, n-1) / n );
350        printf( "%0.3lf\n", ans );
351        return 0;
352}
353*/

354
355
356/*************************************************************
357版本一
358动态规划。
359
360公式变形为 O' * O' = sigma(x[i]*x[i]) / n - avgX * avgX;
361
362对棋盘某局部,左上角为(x1,y1),右下角为(x2,y2),
363
364s[x1][y1][x2][y2]    为此局部的总分的平方,
365d[k][x1][y1][x2][y2] 为此局部切割 k 次所得的最小的 sigma(x[?]*x[?]),
366其中 x[?] 为从此局部中切割出的某块矩形棋盘的分。
367
368
369d[k][x1][y1][x2][y2] = min(
370        min(
371                d[k-1][x1][y1][c][y2] +      s[c+1][y1][x2][y2],
372                     s[x1][y1][c][y2] + d[k-1][c+1][y1][x2][y2]
373        ) 其中 x1 <= c < x2;
374
375        min(
376                d[k-1][x1][y1][x2][c] +      s[x1][c+1][x2][y2],
377                     s[x1][y1][x2][c] + d[k-1][x1][c+1][x2][y2]
378        ) 其中 y1 <= c < y2;
379)
380
381具体见代码。
382*/

383/*
384#include <stdio.h>
385#include <string.h>
386#include <math.h>
387
388#define  L  9
389#define  N  16
390#define  OO 2123456789
391
392int    n, sum[L][L], s[L][L][L][L];
393double d[N][L][L][L][L];
394
395int main(){
396        int    x1, y1, x2, y2, k, c, x;
397        double tem, tt;
398        memset( sum, 0, sizeof(sum) );
399
400        scanf( "%d", &n );
401        for( x1=1; x1<L; ++x1 ){
402                for( y1=1; y1<L; ++y1 ){
403                        scanf( "%d", &x );
404                        sum[x1][y1] = sum[x1-1][y1] + sum[x1][y1-1] - sum[x1-1][y1-1] + x;
405                }
406        }
407
408        for( x1=1; x1<L; ++x1 ){
409                for( y1=1; y1<L; ++y1 ){
410                        for( x2=x1; x2<L; ++x2 ){
411                                for( y2=y1; y2<L; ++y2 ){
412                                        for( k=0; k<n; ++k ){
413                                                d[k][x1][y1][x2][y2] = OO;
414                                        }
415
416                                        x = sum[x2][y2] - sum[x2][y1-1] - sum[x1-1][y2] + sum[x1-1][y1-1];
417                                        d[0][x1][y1][x2][y2] = s[x1][y1][x2][y2] = x * x;
418                                }
419                        }
420                }
421        }
422
423        for( k=1; k<n; ++k ){
424                for( x1=1; x1<L; ++x1 ){
425                        for( y1=1; y1<L; ++y1 ){
426                                for( x2=x1; x2<L; ++x2 ){
427                                        for( y2=y1; y2<L; ++y2 ){
428                                                tem = OO;
429
430                                                for( c=x1; c<x2; ++c ){
431                                                        tt = d[k-1][x1][y1][c][y2] + s[c+1][y1][x2][y2];
432                                                        if( tt < tem ){
433                                                                tem = tt;
434                                                        }
435                                                        tt = s[x1][y1][c][y2] + d[k-1][c+1][y1][x2][y2];
436                                                        if( tt < tem ){
437                                                                tem = tt;
438                                                        }
439                                                }
440
441                                                for( c=y1; c<y2; ++c ){
442                                                        tt = d[k-1][x1][y1][x2][c] + s[x1][c+1][x2][y2];
443                                                        if( tt < tem ){
444                                                                tem = tt;
445                                                        }
446                                                        tt = s[x1][y1][x2][c] + d[k-1][x1][c+1][x2][y2];
447                                                        if( tt < tem ){
448                                                                tem = tt;
449                                                        }
450                                                }
451
452                                                d[k][x1][y1][x2][y2] = tem;
453                                        }
454                                }
455                        }
456                }
457        }
458
459        printf( "%0.3lf\n", sqrt( d[n-1][1][1][8][8] / n - ( sum[8][8] * 1.0 / n ) * ( sum[8][8] * 1.0 / n ) ) );
460        return 0;
461}
462*/

463

posted on 2012-03-17 11:28 coreBugZJ 阅读(567) 评论(0)  编辑 收藏 引用 所属分类: ACMAlgorithm课内作业


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理