日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

PostgreSQL 生成任意基数数独 - 4

發布時間:2023/12/31 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PostgreSQL 生成任意基数数独 - 4 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

標簽

PostgreSQL , 數獨 , 求解 , 動態規劃


背景

使用《PostgreSQL 生成任意基數數獨 - 3》?提供的方法,可以生成有解數獨。在不知道數獨答案的情況下,如何暴力破解呢?

實際上可以修改一下《PostgreSQL 生成任意基數數獨 - 2》?里面的隨機生成數獨的函數,破解數獨。

破解數獨函數如下

create or replace function resolve_sudoku( vsudoku int[] -- 求解數獨 ) returns int[] as $$ declare res int[]; -- 結果 dims int := array_length(vsudoku,1); -- X,Y,BOX集合元素個數 dim int := sqrt(dims); -- 基數 vxyb xyb[]; -- 存儲每個像素在XYB方向上未填充的元素個數 x int; -- 從xyb[]集合中,按指定方法選中一個像素。 X坐標 y int; -- 從xyb[]集合中,按指定方法選中一個像素。 Y坐標 vloops int := 2*dims; -- 計算N次(實際上就是隨機多少次能覆蓋到所有的值,值的取值空間為dims,通常來說執行DIMS次,能覆蓋到所有的隨機數) vloop int :=0; -- 計算N次計數器 cnt int := 0; -- 統計當前數獨總共填充了多少個元素 rand int; -- 隨機值 begin -- 求解 res := vsudoku; loop -- 生成每個像素X,Y,B方向的未知值個數 select comp_xyb(res, dim) into vxyb; -- 選擇下一個要填充的像素(根據未知值個數排行,從總未知值最多,按單軸最多的位置中隨機取一個位置) select ax,ay into x,y from unnest(vxyb) t where t.x+t.y+t.b <> 0 order by (t.x+t.y+t.b) desc , greatest(t.x,t.y,t.b) desc limit 1; -- 如果全部為0,0,0,說明已解完,返回res。 if not found then raise notice '計算有解,計算%次,結束。', cnt; return res; end if; -- 初始化以下計算循環次數 vloop := 0; loop -- 生成隨機值 rand := 1+(random()*(dims-1))::int; -- 這輪循環無法生成并返回空 if vloop >= vloops then raise notice '本像素已循環%次,計算無解。已填充%個元素。無解數獨如下: %', vloop, cnt, res; -- return res; return null; end if; -- 循環次數+1 vloop := vloop+1; -- 橫向驗證 perform 1 where array(select res[x][generate_series(1,dims)]) && array[rand]; if found then continue; end if; -- 縱向驗證 perform 1 where array(select res[generate_series(1,dims)][y]) && array[rand]; if found then continue; end if; -- BOX驗證 perform 1 where array( select res[xx][yy] from (select generate_series(((((x-1)/dim)::int)*dim)+1, ((((x-1)/dim)::int)*dim)+dim) xx) t1, (select generate_series(((((y-1)/dim)::int)*dim)+1, ((((y-1)/dim)::int)*dim)+dim) yy) t2 ) && array[rand]; if found then continue; end if; -- 這個像素值,通過驗證 res[x][y] := rand; -- raise notice 'res[%][%] %', x, y, rand; -- 通過驗證并跳出循環,找下一個需要填充的像素 cnt := cnt+1; exit; end loop; end loop; end; $$ language plpgsql strict volatile;

例子

1、首先按難易程度生成幾個數獨

postgres=# select gen_sudoku_question(20); gen_sudoku_question --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {{1,6,7,9,5,8,4,3,2},{9,5,8,4,3,2,1,6,7},{4,3,2,1,6,7,9,5,8},{6,7,1,5,8,9,3,2,4},{5,8,9,3,2,4,6,7,1},{3,2,4,6,7,1,5,8,9},{7,1,6,8,9,5,2,4,3},{8,9,5,2,4,3,7,1,6},{2,4,3,7,1,6,8,9,5}} {{1,0,7,9,0,8,4,3,2},{9,0,8,0,3,2,0,6,7},{4,3,2,1,6,7,0,5,8},{6,0,1,0,8,9,0,2,4},{5,0,9,3,2,4,0,7,1},{3,2,0,6,7,1,5,8,9},{7,1,0,0,0,5,0,4,3},{0,9,5,2,4,0,7,1,6},{0,4,3,7,0,6,8,9,5}} (2 rows) postgres=# select gen_sudoku_question(41); NOTICE: relation "tmp_sudoku" already exists, skipping gen_sudoku_question --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {{5,3,9,2,6,7,1,4,8},{1,4,8,5,3,9,2,6,7},{2,6,7,1,4,8,5,3,9},{9,5,3,7,2,6,8,1,4},{8,1,4,9,5,3,7,2,6},{7,2,6,8,1,4,9,5,3},{3,9,5,6,7,2,4,8,1},{4,8,1,3,9,5,6,7,2},{6,7,2,4,8,1,3,9,5}} {{5,0,0,2,0,7,1,0,8},{0,4,0,0,0,9,0,6,7},{2,0,7,0,0,0,0,0,0},{9,0,3,0,2,6,8,1,4},{0,1,0,0,0,0,7,0,6},{0,0,6,0,0,0,0,5,3},{0,9,0,6,0,2,4,0,1},{4,8,0,0,9,0,6,7,2},{6,0,2,4,0,1,0,0,5}} (2 rows) postgres=# select gen_sudoku_question(51); NOTICE: relation "tmp_sudoku" already exists, skipping gen_sudoku_question --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {{3,4,5,8,1,6,2,9,7},{8,1,6,2,9,7,3,4,5},{2,9,7,3,4,5,8,1,6},{4,5,3,1,6,8,9,7,2},{1,6,8,9,7,2,4,5,3},{9,7,2,4,5,3,1,6,8},{5,3,4,6,8,1,7,2,9},{6,8,1,7,2,9,5,3,4},{7,2,9,5,3,4,6,8,1}} {{0,4,5,0,0,6,2,9,0},{8,1,0,0,0,0,0,4,0},{2,0,0,3,4,0,8,0,6},{0,0,3,1,6,8,0,0,0},{0,0,8,0,0,0,4,5,0},{0,0,0,4,0,0,1,6,0},{0,0,0,0,0,1,0,0,9},{6,0,0,7,0,0,0,3,4},{0,0,0,0,0,0,0,0,1}} (2 rows)

2、使用上面創建的函數破解數獨
填充20個值的數獨基本上秒解。

postgres=# select res from (select resolve_sudoku('{{1,0,7,9,0,8,4,3,2},{9,0,8,0,3,2,0,6,7},{4,3,2,1,6,7,0,5,8},{6,0,1,0,8,9,0,2,4},{5,0,9,3,2,4,0,7,1},{3,2,0,6,7,1,5,8,9},{7,1,0,0,0,5,0,4,3},{0,9,5,2,4,0,7,1,6},{0,4,3,7,0,6,8,9,5}}'::int[]) res from generate_series(1,100) ) t where t.res is not null ; res --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {{1,6,7,9,5,8,4,3,2},{9,5,8,4,3,2,1,6,7},{4,3,2,1,6,7,9,5,8},{6,7,1,5,8,9,3,2,4},{5,8,9,3,2,4,6,7,1},{3,2,4,6,7,1,5,8,9},{7,1,6,8,9,5,2,4,3},{8,9,5,2,4,3,7,1,6},{2,4,3,7,1,6,8,9,5}} (1 row)

但是對于需要填充41個,51個的,這種暴力嘗試的方式,跑1000次也解不出來。

還是需要一個非常行之有效的。

目前的暴力破解存在的問題,一個值一旦確定下來(XYB方向滿足約束)之后,后面就不會去修正它,從而導致了一個錯誤后面的計算全是浪費的。增加了破解成本。

擴展

在數據庫中執行計劃也與之類似,目前大多數執行計劃是靜態的,一旦執行計劃確定下來了,后面就只能按照執行計劃執行,無法中途調整。

所以,動態執行計劃也成為目前很多數據庫優化器突破的方向,在執行過程中,根據執行過程中的統計信息,不斷修正執行計劃,達到最佳的目的。

實際上,導航也與之類似,如果你根據當前的路況規劃好了導航,在行駛過程中,可能某些路段發生了變化(擁堵情況),靜態導航就無法修正這樣的問題,還是按一開始既定的線路行駛。而動態導航,可以根據實時路況進行修正,選擇下一跳。

在生產中有很多類似的例子,比如數據路由,負載均衡等等。

總結

以上是生活随笔為你收集整理的PostgreSQL 生成任意基数数独 - 4的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。