【轉】第六屆藍橋杯決賽 第二題 完美正方形 (線段樹)
阿新 • • 發佈:2019-02-04
完美正方形
如果一些邊長互不相同的正方形,可以恰好拼出一個更大的正方形,則稱其為完美正方形。歷史上,人們花了很久才找到了若干完美正方形。比如:如下邊長的22個正方形
2 3 4 6 7 8 12 13 14 15 16 17 18 21 22 23 24 26 27 28 50 60
如【圖1.png】那樣組合,就是一種解法。此時,
緊貼上邊沿的是:60 50
緊貼下邊沿的是:26 28 17 21 18
22階完美正方形一共有8種。下面的組合是另一種:
2 5 9 11 16 17 19 21 22 24 26 30 31 33 35 36 41 46 47 50 52 61
如果告訴你該方案緊貼著上邊沿的是從左到右依次為:47 46 61,
你能計算出緊貼著下邊沿的是哪幾個正方形嗎?
請提交緊貼著下邊沿的正方形的邊長,從左到右,用空格分開。
答案:50 33 30 41
#include <iostream> #include <String.h> using namespace std; int a[]={2, 5 ,9 ,11 ,16, 17, 19, 21, 22, 24, 26, 30, 31, 33, 35, 36, 41, 50 ,52 }; //正方形 int vis[19]; //訪問陣列 int que[30]; // 儲存最下行每個正方形大小 int fon=0; //最下行正方形索引 int map[154][154]; //填充為1 未填充為0 void make(int x,int y,int k,int u) //填充和清除正方形 u為1為填充 否則為清空 { if(u==1) for(int i=x;i<x+k;i++) for(int j=y;j<y+k;j++) { map[i][j]=1; } else for(int i=x;i<x+k;i++) for(int j=y;j<y+k;j++) { map[i][j]=0; } } int panduan(int x,int y,int k) // 當前點 x y 填充大小k { if(x+k>154)return 0; if(y+k>154)return 0; //判斷將被填入的正方形部分是否有已經被填充部分 for(int i=x;i<x+k;i++) for(int j=y;j<y+k;j++) { if(map[i][j]==1)return 0; } return 1; } int f(int k) //k為遍歷陣列的索引 { if(k>=19) //完成遍歷 { for(int i=0;i<fon;i++) cout<<que[i]<<" "; cout<<endl; return 1; } for(int j=0;j<154;j++) for(int i=0;i<154;i++) { if(map[i][j]==0) //如果未填充 { for(int z=0;z<19;z++) //搜尋陣列中的正方形 { if(vis[z]==0 && panduan(i,j,a[z])) //如果正方形未使用並且符合填充要求 { int flog=0; if(i+a[z]==154) { que[fon++]=a[z]; flog=1; } vis[z]=1; make(i,j,a[z],1); if(f(k+1)) return 1; //如果滿足要求填充下一塊 if(flog) //如果填過一塊,從前一塊開始填 fon--; vis[z]=0; make(i,j,a[z],0); } } return 0; } } return 0; } int main() { make(0,0,47,1);make(0,47,46,1);make(0,93,61,1); f(0); return 0; }