天天看點

完美的正方形分割

完美的正方形分割:http://learning.sohu.com/20060329/n242511178.shtml

問題出處:http://topic.csdn.net/u/20071206/17/20f9fb73-7a11-4fab-92a4-f7a61a056c3f.html

解決辦法:

先窮舉出可能的正方形組合1   ,然後檢測能不能拼成指定長方形2

程式用遞歸實作

1可能的組合:各正方形面積和與某個長方形面積相等,進行第一輪篩選

2就像用計算機玩隻有大小不一的正方形的俄羅斯方塊一樣,搜尋有沒有解

c源代碼:

完美的正方形分割

#include  < stdio.h >

完美的正方形分割

#include  < math.h >

完美的正方形分割

#include  < time.h >

完美的正方形分割

#include  < assert.h >

完美的正方形分割
完美的正方形分割

const  MAXWIDTH  =   200 ;     // 最大寬度

完美的正方形分割

const  MAXBASE  =   3 ;         // 最小正方形最大尺寸

完美的正方形分割

const  RANK  =   10 ;         // 階數

完美的正方形分割

const  MARGIN  =   10 ;         // 長寬最大內插補點(0表示正方形)

完美的正方形分割
完美的正方形分割

int  square[MAXWIDTH];     // NUM個數的平方,優化效果微小

完美的正方形分割

int  result[RANK];         // 可能的排列結果【0, rank-1】,從小到大

完美的正方形分割
完美的正方形分割

int  width, height;         // 寬、高

完美的正方形分割

int  count  =   0 ;             // 窮舉記數

完美的正方形分割
完美的正方形分割

int  flag[RANK];             // 代表被使用的順序号(索引);值[0,rank-1],rank表示未使用,>rank做标記用于輸出結果,例:flag[RANK-1]=0,表示最大的正方形放第一個

完美的正方形分割

int  high[MAXWIDTH];         // 已被填放的高度表,比如9×10的長方形放置一個5×5,則資料為:[5 5 5 5 5 0 0 0 0 0] 

完美的正方形分割

// 注意:這兩個數組用于遞歸,每個遞歸使用退出後需要還原原值

完美的正方形分割
完美的正方形分割

void  perfectrect();

完美的正方形分割

void  check();

完美的正方形分割

void  search( int  n,  int  index,  int  sum);                     // 枚舉正方形組合

完美的正方形分割

bool  searchrect( int  n,  int  left);     // 判斷能否填充

完美的正方形分割
完美的正方形分割

int  main( int  argc,  char   *  argv[])

完美的正方形分割
完美的正方形分割

... {

完美的正方形分割

    int i;

完美的正方形分割
完美的正方形分割

    //預處理

完美的正方形分割

    for(i=1; i<=MAXWIDTH; i++)

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        square[i] = i * i;

完美的正方形分割

    }

完美的正方形分割

    perfectrect();

完美的正方形分割
完美的正方形分割

    printf("Complete! ");

完美的正方形分割
完美的正方形分割

    return 0;

完美的正方形分割

}

完美的正方形分割
完美的正方形分割

void  perfectrect()

完美的正方形分割
完美的正方形分割

... {

完美的正方形分割

    int sum;

完美的正方形分割

    int i;

完美的正方形分割

    static count2 = count;

完美的正方形分割

    time_t t;

完美的正方形分割

    time_t t2 = 0;

完美的正方形分割
完美的正方形分割

    for(width=20; width<MAXWIDTH; width++) 

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        for(height=width; height<=width+MARGIN; height++)

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            sum = height*width;            

完美的正方形分割

            for(i=1; i<=MAXBASE; i++)

完美的正方形分割
完美的正方形分割

            ...{

完美的正方形分割

                result[0] = i;

完美的正方形分割

                search(i+1,1, sum-square[i]);

完美的正方形分割

            }

完美的正方形分割

        }

完美的正方形分割
完美的正方形分割

        t = clock();

完美的正方形分割

        printf("%d %10d %10d %10d %10d ", width, count, t, count-count2, t-t2);

完美的正方形分割

        count2 = count;

完美的正方形分割

        t2 = t;

完美的正方形分割

    }

完美的正方形分割

}

完美的正方形分割
完美的正方形分割
完美的正方形分割
完美的正方形分割
完美的正方形分割

void  search( int  n,  int  index,  int  sum)

完美的正方形分割
完美的正方形分割

... {

完美的正方形分割

    int i;

完美的正方形分割
完美的正方形分割

    for(i=n;sum >=square[i]*(RANK-index); i++)  

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        if(index == RANK-1 )

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            if(sum == square[i]) 

完美的正方形分割
完美的正方形分割

            ...{

完美的正方形分割

                result[index] = i;

完美的正方形分割

                check();

完美的正方形分割

                break;

完美的正方形分割

            }

完美的正方形分割

        }

完美的正方形分割

        else 

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            result[index] = i;

完美的正方形分割

            search(i+1, index+1, sum-square[i]);

完美的正方形分割

        }

完美的正方形分割

    }

完美的正方形分割

}

完美的正方形分割
完美的正方形分割
完美的正方形分割

// 判斷能否拼成指定長方形

完美的正方形分割

void  check() 

完美的正方形分割
完美的正方形分割

... {

完美的正方形分割

    count++;

完美的正方形分割
完美的正方形分割

    int i, tmp;

完美的正方形分割
完美的正方形分割

    for(i=0; i<RANK-1; i++)

完美的正方形分割

        flag[i] = RANK; //未使用

完美的正方形分割
完美的正方形分割

    //第一個放置最大的

完美的正方形分割

    flag[RANK-1] = 0;   

完美的正方形分割

    tmp = result[RANK-1];

完美的正方形分割

    for(i=0; i<tmp; i++)

完美的正方形分割

        high[i] = tmp;

完美的正方形分割
完美的正方形分割

    //放置第二個正方形,遞歸搜尋

完美的正方形分割

    searchrect(1, tmp);

完美的正方形分割

}

完美的正方形分割
完美的正方形分割
完美的正方形分割
完美的正方形分割
完美的正方形分割

bool  searchrect( int  n,  int  left)

完美的正方形分割
完美的正方形分割

... {

完美的正方形分割

    int i, j;

完美的正方形分割

    int pos, w, h; //最低處起始位置,高度,寬度

完美的正方形分割

    int tmp;

完美的正方形分割
完美的正方形分割
完美的正方形分割

    //對第一行優化處理

完美的正方形分割

    if(left != 0)    

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        for(i=RANK-2; i>=0; i--) //從大到小放置([RANK-1]已被使用)

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            if(flag[i] < n)//是否已使用

完美的正方形分割

                continue;  

完美的正方形分割
完美的正方形分割

            if(result[i] > width-left) //放不下,下一個

完美的正方形分割

                continue;

完美的正方形分割
完美的正方形分割

            flag[i] = n;   

完美的正方形分割

            tmp = result[i];

完美的正方形分割

            for(j=0; j<tmp; j++)

完美的正方形分割

                high[j+left] = tmp;

完美的正方形分割
完美的正方形分割

            if(tmp == width-left)   //相等,搜尋第二行

完美的正方形分割
完美的正方形分割

            ...{

完美的正方形分割

                if(searchrect(n+1, 0))  //成功

完美的正方形分割
完美的正方形分割

                ...{

完美的正方形分割

                    flag[i] = RANK;   //恢複标記

完美的正方形分割

                    return true;

完美的正方形分割

                }

完美的正方形分割

            }

完美的正方形分割

            else //繼續第一行

完美的正方形分割
完美的正方形分割

            ...{

完美的正方形分割

                if(searchrect(n+1, left+tmp))  //成功

完美的正方形分割
完美的正方形分割

                ...{

完美的正方形分割

                    flag[i] = RANK;   //恢複标記

完美的正方形分割

                    return true;

完美的正方形分割

                }

完美的正方形分割

            }

完美的正方形分割

            flag[i] = RANK;     //恢複标記

完美的正方形分割

        }

完美的正方形分割
完美的正方形分割

        return false;

完美的正方形分割

        //assert(!"第一行排列出錯");

完美的正方形分割

    }//是否第一行

完美的正方形分割
完美的正方形分割
完美的正方形分割

    //非第一行

完美的正方形分割

    //擷取插入位置和大小

完美的正方形分割

    h = height+1;

完美的正方形分割

    bool exist = false;

完美的正方形分割
完美的正方形分割

    for(i=0; i<width; i++)

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        if(exist && high[i] == h)

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            w++;

完美的正方形分割

        }

完美的正方形分割

        else if(high[i] < h)

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            h = high[i];

完美的正方形分割

            pos = i;

完美的正方形分割

            w = 1;

完美的正方形分割

            exist = true;

完美的正方形分割

        }

完美的正方形分割

        else  //防止最底的位置存在兩塊(不連續)

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            exist = false;

完美的正方形分割

        }

完美的正方形分割

    }

完美的正方形分割
完美的正方形分割

    //周遊

完美的正方形分割

    for(i=RANK-2; i>=0; i--) //從大到小放置([RANK-1]已被使用)

完美的正方形分割
完美的正方形分割

    ...{

完美的正方形分割

        if(flag[i] < n)//是否已使用

完美的正方形分割

            continue;  

完美的正方形分割
完美的正方形分割

        if(n == RANK-1) //完美長方形

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            if(w == result[i] && height == h+result[i])

完美的正方形分割
完美的正方形分割

            ...{

完美的正方形分割

                for(j=0; j<RANK-1; j++)

完美的正方形分割
完美的正方形分割

                ...{

完美的正方形分割

                    for(int k=0; k<RANK; k++)

完美的正方形分割

                        if(flag[k]==j)

完美的正方形分割

                            printf("%d, ", result[k]);

完美的正方形分割

                }

完美的正方形分割

                printf("%d ", result[i]);

完美的正方形分割

                return true;

完美的正方形分割

            }

完美的正方形分割

            else

完美的正方形分割

                continue;

完美的正方形分割

        }

完美的正方形分割
完美的正方形分割

        if(w < result[i]) //放不下,下一個

完美的正方形分割

            continue;

完美的正方形分割
完美的正方形分割

        tmp = result[i];

完美的正方形分割

        if(height < h+tmp)  //高越界

完美的正方形分割

            continue;

完美的正方形分割
完美的正方形分割

        flag[i] = n;   

完美的正方形分割
完美的正方形分割

        for(j=0; j<tmp; j++)

完美的正方形分割

            high[j+pos] += tmp ;

完美的正方形分割
完美的正方形分割

        if(searchrect(n+1, 0))  //成功

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            flag[i] = RANK;   //恢複标記

完美的正方形分割

            for(j=0; j<tmp; j++)

完美的正方形分割

                high[j+pos] -= tmp ;

完美的正方形分割

            return true;

完美的正方形分割

        }

完美的正方形分割

        else //不成功,恢複标記後轉下一個

完美的正方形分割
完美的正方形分割

        ...{

完美的正方形分割

            flag[i] = RANK;    

完美的正方形分割

            for(j=0; j<tmp; j++)

完美的正方形分割

                high[j+pos] -= tmp ;

完美的正方形分割

        }

完美的正方形分割

    }//逐個判斷

完美的正方形分割
完美的正方形分割

    return false;

完美的正方形分割

}     

完美的正方形分割

10階完美分割輸出:

20         10         15         10         15

21         32         15         22          0

22         73         15         41          0

23        128         15         55          0

24        225         31         97         16

25        443         46        218         15

26        775         62        332         16

27       1225         93        450         31

28       1963        156        738         63

29       3106        250       1143         94

30       4817        359       1711        109

31       7182        546       2365        187

32      10608        765       3426        219

33      15306       1140       4698        375

34      22150       1609       6844        469

35      31782       2296       9632        687

36      42902       3015      11120        719

37      59456       4296      16554       1281

38      81354       5859      21898       1563

39     108661       7968      27307       2109

40     144732      10375      36071       2407

41     192230      14218      47498       3843

42     251482      18562      59252       4344

43     327179      24734      75697       6172

44     419013      31546      91834       6812

45     536701      41125     117688       9579

46     684991      52875     148290      11750

47     865802      68468     180811      15593

48    1075802      84421     210000      15953

49    1349101     108109     273299      23688

50    1683193     135531     334092      27422

51    2067328     169343     384135      33812

52    2529166     207343     461838      38000

53    3100325     258562     571159      51219

54    3760772     315031     660447      56469

30, 25, 8, 17, 27, 3, 11, 2, 15, 13

暴力窮舉第一個需要300多秒

而9階的第二個不到300秒,第一個隻用0.3秒(修改const RANK = 9)

11階還不知道多少時間,暫時也想不出怎麼優化,也許隻能從數學上想辦法了

那個本世紀三十年代末的德國數學家太猛了