分治法2
来源:互联网 发布:英雄传奇挂机软件 编辑:程序博客网 时间:2024/06/14 17:18
Chess-Board
问题描述:有
问题分析:首先所给的4个card是可以将最小矩形的三个块组合的所有情况都考虑到了
代码实现:
# Import a library of functions called 'pygame'import pygameimport time# Define the colors we will use in RGB formatBLACK = (0, 0, 0)WHITE = (255, 255, 255)BLUE = (0, 0, 255)GREEN = (0, 255, 0)RED = (255, 0, 0)YELLOW = (255, 255, 0)Colors = [RED, BLUE, GREEN, YELLOW]# define a global queue named BoardsBoards = []def Card(tag, left_upper): """ tag:card的类型,为0就代表第一个方块为空,同理类推 left_upper:card所在矩形左上角的坐标 """ global Boards blocks = [] nums = [0, 1, 2, 3] nums.remove(tag) for i in nums: block = [] row = int(i / 2) col = i % 2 block.append((left_upper[1] + col) * 40 + 10) block.append((left_upper[0] + row)*40 + 10) block.append(40) block.append(40) blocks.append(block) blocks.append(Colors[tag]) Boards.append(blocks)def DrawBoard(dr, dc, size): pygame.init() window_size = [size * 40 + 20, size * 40 + 20] # Set the height and width of the screen screen = pygame.display.set_mode(window_size) pygame.display.set_caption("chess board") done = False clock = pygame.time.Clock() while not done: # This limits the while loop to a max of 10 times per second. # Leave this out and we will use all CPU we can. clock.tick(10) for event in pygame.event.get(): # User did something if event.type == pygame.QUIT: # If user clicked close done = True # 画出相应的grid screen.fill(WHITE) for i in range(size + 1): pygame.draw.line(screen, BLACK, [i * 40 + 10, 10], [i * 40 + 10, size * 40 + 10], 3) pygame.draw.line(screen, BLACK, [10, i * 40 + 10], [size * 40 + 10, i * 40 + 10], 3) # Draw a rectangle outline pygame.draw.rect(screen, RED, [dc * 40 + 10,dr * 40 + 10, 40, 40], 0) for L in Boards: pygame.draw.rect(screen, L[3], L[0], 0) pygame.draw.rect(screen, L[3], L[1], 0) pygame.draw.rect(screen, L[3], L[2], 0) time.sleep(2) pygame.display.flip() pygame.display.flip() # Be IDLE friendly # pygame.quit()def chBoard(tr, tc, dr, dc, size): """ 坐标都是从0开始的 tr:表示要处理的子方格的左上角横坐标 tc:表示要处理的子方格的左上角竖坐标 dr:表示特殊方块的row dr:表示特殊方块的col size:表示问题的规模(2^k) """ global tile tile += 1 s = size / 2 # 判断特殊方块落在哪个区域 num_row = 0 if ((dr - tr) < s) else 1 num_col = 0 if ((dc - tc) < s) else 1 k = num_row * 2 + num_col # 填补中心点的另外三个方块 Card(k, [tr + s - 1, tc + s - 1]) if (s == 1): return # 分别对四个区域进行处理 # 左上角覆盖 if (k == 0): chBoard(tr, tc, dr, dc, s) else: chBoard(tr, tc, tr + s - 1, tc + s - 1, s) # 右上角覆盖 if (k == 1): chBoard(tr, tc + s, dr, dc, s) else: chBoard(tr, tc + s, tr + s - 1, tc + s, s) # 左下角覆盖 if (k == 2): chBoard(tr + s, tc, dr, dc, s) else: chBoard(tr + s, tc, tr + s, tc + s - 1, s) # 右下角覆盖 if (k == 3): chBoard(tr + s, tc + s, dr, dc, s) else: chBoard(tr + s, tc + s, tr + s, tc + s, s)if __name__ == "__main__": tile = 0 chBoard(0, 0, 3, 5, 16) print(Boards) DrawBoard(3,5,16)
从上面的代码可以看出:
这里将一个大问题分解成了四个小问题,但是四个小问题,由于特殊块是否在其中,又呈现出两种不同的形态(区别在于特殊块);
通过可视化,我们可以发现在填充时也是一个区域内,不断递归式的进行填充。
这个问题的复杂度为
找到第K个最小数
问题:在一组无序的数中,找到第K个最小数,同时要在
解决方法:借用快速排序的思想,每次我们确定一个轴点,如果这个轴点是第k个,就返回其值;否则不是就转到相应的子区间内,寻找。这样问题的复杂度就可以降为
通过进一步分析,可以发现最坏的情况复杂度为
出现上面情况的主要原因在轴点划分的十分不均匀,所以我们可以采取下列措施使得轴点划分的十分均匀:
1. 将所有的元素划分成5个一组,一共
2. 对每个组进行排序
3. 抽取每个组的中间元素,组成一个新的向量,一共
4. 返回第一步进行循环,直到size为1。
5. 返回这个x。这个x就是partition的x。
整体的代码如下所示:
#include<iostream>#include<vector>using namespace std;void PopSort(vector<int> &A ,int start,int end){ for (int j = start; j < end; j++){ for (int i = 0; i < end-j-1; i++){ if (A[i + start] > A[i + start + 1]){ int temp = A[i + start]; A[i + start] = A[i + start + 1]; A[i + start + 1] = temp; } } }}int Partition(vector<int> &A, int start, int end){ int axis_point = A[start]; while (start < end){ while (A[end] >= axis_point && start < end) end--; A[start] = A[end]; while (A[start] <= axis_point && start < end) start++; A[end] = A[start]; } A[start] = axis_point; return start;}//这里求的是第k个最大的,但是vector的index是从0开始的int Findkelement(vector<int> &A, int start, int end, int k){ if (start == end) return A[start]; int prvo = Partition(A, start, end); int j = prvo - start + 1; if (k == j) return A[prvo]; if (k < j) return Findkelement(A, start, prvo-1, k); //如果这里不减1,当prvo等于1,k=1的时候,就进入了死循环。 else return Findkelement(A, prvo + 1, end, k - j);}//改良后的代码int Select(vector<int> &A, int k){ //元素少于75的没有必要用复杂的复杂的方法。 if (A.size() < 75) return Findkelement(A, 0, A.size() - 1, k); //分组并进行排序 int groups = (A.size() + 4) / 5; for (int i = 0; i < groups-1; i++){ PopSort(A, i * 5, (i + 1) * 5); } PopSort(A, (groups - 1) * 5, A.size()); vector<int> Median; for (int j = 0; j < groups-1; j++){ Median.push_back(A[3 + j * 5]); } Median.push_back(A[(groups - 1) * 5]); //选出median的中位数 int x = Select(Median, (Median.size()+1) / 2); //根据中位数对元素进行分组 vector<int> S1, S2; for (int i = 0; i < A.size(); i++){ if (A[i] <= x) S1.push_back(A[i]); else S2.push_back(A[i]); } int value=0; //在对应的分组中继续找对应的元素 if (k <= S1.size()) return Select(S1, k); else return Select(S2, k - S1.size());//这里必须要添加return否则就会有逻辑错误。}void main(){ vector<int> A = { 3, 4, 5, 6, 7, 8,3,4,5,6,7,8,43,3,4,5,6,7,8,3,2,7,4,3,45,5,6,4,3,5,6,5,4,3,5,6,7,8,65,5,3,3,5,6,7,7,45,4,4,3,5,6,4,3,54,6,4,6,4,3,6,7,6,5,4,23,34,5,6,6,7,5,5,4,4,3,4,5,6,5,4,3,3,4,5,6,4,4,5,6,78,8,6,5,54,4,5,6,6,4,4,3, 92, 4, 6, 8, 0, 4, 2 }; cout << Select(A,109) << endl;}
对上面的算法进行复杂度分析:
1. 对于M这个数组的中位数x,至少有
2. 而小于的每个数在A中至少大于等于3个数,所以在A中只有
3. 当
4. 所以从3中我们可以看出为什么是5的原因,在这里5,75是相互对应的。