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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021 9.14 p.m.小结 以及 数独问题探索(T3)

發(fā)布時間:2023/12/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021 9.14 p.m.小结 以及 数独问题探索(T3) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

T1:問題 A: 組合的輸出

題目描述

排列與組合是常用的數(shù)學方法,其中組合就是從 n 個元素中抽出 r 個元素(不分順序且 r<=n),我們可以簡單地將 n 個元素理解為自然數(shù) 1,2,…,n,從中任取 r 個數(shù)。
現(xiàn)要求你用遞歸的方法輸出所有組合。
例如 n=5,r=3,所有組合為:
l 2 3 l 2 4 1 2 5 l 3 4 l 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5

輸入

一行兩個自然數(shù) n、r(1<n<21,1<=r<=n)。

輸出

所有的組合,每一個組合占一行且其中的元素按由小到大的順序排列,每個元素占三個字符的位置,所有的組合也按字典順序。

樣例輸入

5 3

樣例輸出

??1 ?2 ?3

??1 ?2 ?4

??1 ?2 ?5

??1 ?3 ?4

??1 ?3 ?5

??1 ?4 ?5

??2 ?3 ?4

??2 ?3 ?5

??2 ?4 ?5

??3 ?4 ?5

題解

這道題考察了排列數(shù)的問題。只需要用一個pd數(shù)組來枚舉每一層(每一位)選什么數(shù),再用一個VIS數(shù)組來記錄是否選過,若沒選則選,否則下一個。注意可能用快讀快寫優(yōu)化時間。

參考代碼

#include<cstdio> using namespace std; int n,r,x[100],vis[100]; void dfs(int k) {if(k==r+1){for(int i=1;i<=r;i++)printf("%3d",x[i]);printf("\n");return ;}for(int i=x[k-1]+1;i<=n;i++){if(!vis[i]){vis[i]=1;x[k]=i;dfs(k+1);vis[i]=0;}} } int main() {scanf("%d%d",&n,&r);dfs(1);return 0; }

T2:問題 B: 門票問題

題目描述

??? 有很多人在門口排隊,每個人將會被發(fā)到一個有效的通行密碼作為門票。一個有效的密碼由L(3≤L≤15)個小寫英文字母組成,至少有一個元音(a、e、i、o或u)和兩個輔音(除去元音以為的音節(jié)),并且是按字母表順序出現(xiàn)的(例如abc是有效的,而bac不是)。
??? 現(xiàn)在給定一個期望長度為L和C(1≤C≤26)個小寫字母,寫一個程序,輸出所有的長度為L、能由所給頂?shù)腃個字母組成的有效密碼。密碼必須按字母表順序打印出來,一行一個。

輸入

??? 第1行是兩個由一個空格分開的正整數(shù),L和C,3≤L≤15,1≤C≤26。
??? 第2行是C個由一個空格隔開的小寫字母密碼是由這個字母集中的字母來構(gòu)建的。

輸出

??? 若干行,每行輸出一個長度為L個字符的密碼(沒有空格)。輸出行必須按照字母順序排列。程序只需要輸出前25000個有效密碼,即使后面還存在有效密碼。

樣例輸入

4 6

a t c i s w

樣例輸出

acis

acit

aciw

acst

acsw

actw

aist

aisw

aitw

astw

cist

cisw

citw

istw

題解

本題與上一道題相比,多了一些要求:至少一個元音,2個輔音。因此我們可以在搜索的過程中來剪枝。首先可以維護一個前綴和(倒著的),表示后面元音的個數(shù)。搜索過程中,如果當前枚舉到了k,前面沒有元音,而后面也沒有元音了(前綴和),那么就可以直接return。同理,輔音的處理與這個類似,只不過是個數(shù)<2。同時如果接下來的字母都用上,還達不到既定長度,那么也return。有了3重剪枝,就能極大的優(yōu)化時間效率。

參考代碼

#include<cstdio> #include<algorithm> using namespace std; int l,c,x[100],seg[500],p[100],vis[100],tot=0; char s[100];int pd1[500],pd2[500],sis=0,ht[500]; bool pd(int k) { return k=='a'||k=='e'||k=='i'||k=='o'||k=='u'; } void dfs(int k) {if(tot>25000) return;pd1[k]=pd1[k-1];pd2[k]=pd2[k-1];if(k==l+1){if(pd1[k]==0||pd2[k]<2) return;tot++;if(tot>25000) return;for(int i=1;i<=l;i++)putchar(p[i]);printf("\n");return;}for(int i=seg[p[k-1]]+1;i<=c;i++){if(tot>25000) return;if(vis[i]) continue;if(i==sis&&pd1[k]==0) break;if(pd2[k]+ht[i]<2) break;if(c-i+1+k<l) break;vis[i]=1;p[k]=x[i];if(pd(x[i])) {pd1[k]++;dfs(k+1);pd1[k]--;}else{pd2[k]++;dfs(k+1);pd2[k]--;}vis[i]=0;} } int main() {scanf("%d%d",&l,&c);for(int i=1;i<=c;i++){scanf("%s",s);x[i]=s[0];} sort(x+1,x+c+1);for(int i=c;i>=1;i--) {seg[x[i]]=i;ht[i]=ht[i+1];if(pd(x[i])&&sis==0)sis=i+1;if(!pd(x[i]))ht[i]++;}dfs(1);return 0; }

T3:問題 C: 子集和問題

題目描述

子集和問題的一個實例為〈S,c〉。其中,S={ x1, x2,…, xn}是一個正整數(shù)的集合,c是一個正整數(shù)。子集和問題判定是否存在S的一個子集S1,使得子集S1和等于c。
對于給定的正整數(shù)的集合S={ x1, x2,…, xn}和正整數(shù)c,編程計算S 的一個子集S1,使得子集S1和等于c。

輸入

第1行有2個正整數(shù)n和c,n表示S的個數(shù),c是子集和的目標值。

接下來的1 行中,有n個正整數(shù),表示集合S中的元素。

n<=8000 c<=10^7

輸出

子集,各元素之間用空格隔開。當問題無解時,輸出“No solution!”。

樣例輸入

5 10

2 2 6 5 4

樣例輸出

2 2 6

題解

這道題忽略數(shù)據(jù)范圍吧。現(xiàn)在只考慮怎么完成這道題。同樣的,用一個pd數(shù)組維護sum,如果sum=c就全部return。當然,還要用x數(shù)組記錄所選的元素。這樣還不夠,需要一點小剪枝。如果此刻的sum大于c,return;如果后面的數(shù)的和加上sum都小于c,那么也沒必要繼續(xù)搜了,直接return。如此就能找到一組答案就退出,或者輸出問題無解。

參考代碼

#include<cstdio> #define LL long long using namespace std; int n,c,a[10000],sum=0,sum1[10000]; int pd=0,x[10000]; void dfs(int k) {if(sum+sum1[n]-sum1[x[k-1]]<c) return;if(pd==1) return;if(sum==c){for(int i=1;i<k;i++) printf("%d ",a[x[i]]);pd=1;return;}for(int i=x[k-1]+1;i<=n;i++){x[k]=i;if(sum+a[i]>c) continue;sum+=a[i];dfs(k+1);sum-=a[i];} } int main() {scanf("%d%d",&n,&c);for(LL i=1;i<=n;i++) {scanf("%d",&a[i]);sum1[i]=sum1[i-1]+a[i];}dfs(1);if(pd==0) printf("No Solution!");return 0; }

T5:問題 E: 數(shù)獨

題目描述

數(shù)獨是一種傳統(tǒng)益智游戲,你需要把一個9 × 9的數(shù)獨補充完整,使得圖中每行、每列、每個3 × 3的九宮格內(nèi)數(shù)字1~9均恰好出現(xiàn)一次。

請編寫一個程序填寫數(shù)獨。

?

輸入

輸入包含多組測試用例。

每個測試用例占一行,包含81個字符,代表數(shù)獨的81個格內(nèi)數(shù)據(jù)(順序總體由上到下,同行由左到右)。

每個字符都是一個數(shù)字(1-9)或一個”.”(表示尚未填充)。

您可以假設(shè)輸入中的每個謎題都只有一個解決方案。

文件結(jié)尾處為包含單詞“end”的單行,表示輸入結(jié)束。

輸出

每個測試用例,輸出一行數(shù)據(jù),代表填充完全后的數(shù)獨。

樣例輸入

.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.

......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.

樣例輸出

527389416819426735436751829375692184194538267268174593643217958951843672782965341

416837529982465371735129468571298643293746185864351297647913852359682714128574936

題解

????????對于這道題我也算是頗有心得。我的代碼對于單個的九宮格不輸任何表答,但就是要跑2s!!所有我這個代碼無法過數(shù)獨這道題(淚流滿面,蒟蒻的悲傷~)。現(xiàn)在來談?wù)勥@道題。首先用一個e_map存一下地圖,然后把每一行、每一列、每一個3*3方塊壓縮成二進制保存下來。再把每一行還沒有填的格子記錄一下(這樣就不用重復找已經(jīng)填過的數(shù)),然后就搜唄。

????????搜的話很簡單了,只用在(橫著的沒填的、豎著的沒填的、方塊里沒填的)求交集,然后枚舉數(shù)字即可。注意,是!沒!填!的!因此我們直接把之前二進制壓縮的結(jié)果亦或(^)511(二進制111111111)就可以了,相當于全部取個反(現(xiàn)實意義)。處理了這一位的數(shù)字后,來考慮下一次枚舉那一個位置。這時我就直接用了一個!!!大優(yōu)化!!!就是每次把每一行能取的位置倒著枚舉,然后……直接取,并且把當前行的總共能填的總數(shù)-1,并且在回溯之后加回去就可以了。這一步十分精妙,可以動態(tài)剪枝,并且由于我的每一行總數(shù)組不變,變的只是尾指針,因此答案也是正確的,這部分參見代碼中search函數(shù)。

?????????為了進一步優(yōu)化,我還用冒泡排序(個人認為應(yīng)該用快排,可能會快一些,但是……寫不來那種)把每一行的能取的位置排了個序,關(guān)鍵字就是這個位置能填的數(shù)的可能性,可能性越小,說明需要回溯的機會越少,也就能越快的找到答案。還有一個明顯的優(yōu)化,就是找到了唯一的一組解后,直接return,并且要讓所有正在運行的函數(shù)全部return,因此我定義了ed,當ed=1時,表示答案已找到,此時我在大量的區(qū)域做了ed的判斷(其實就2處),加快return的速度。對于找數(shù)字,此處還運用了lowbit的知識來優(yōu)化選擇,有興趣者可以自行查閱,不用lowbit也能跑,for就行了,但是時間效率就會損失的比較多。

????????還有一點,用tot存一下此刻還有多少空格沒有選,當tot=0時表示答案已經(jīng)出現(xiàn),此刻更新ed,并且輸出答案。特別注意各個函數(shù)的初始化,這點十分重要。至于那幾個輸出的函數(shù),只是為了驗算一些東西,可自行理解。如何處理3*3的塊?如果看過代碼(…………此處省略一萬字),就能發(fā)現(xiàn)我的數(shù)組的更新就解釋了這一點。(x+2)/3能夠準確表示這是上中下的那一塊區(qū)域,同理對于y也能確定在哪一豎行。

????????代碼最后可以計算出單純dfs的運行時間,我就是通過這個來判斷時間的,注意最后的輸出毫秒是浮點數(shù),要用ctime的頭文件。最后為了提速,還用了各種方法,只是效果皆不明顯,此處就省略了。最后注意!!!這代碼能很快求一個的答案,卻沒法過!!!?

? ? ? ? 對了,這個代碼最后有很多我自己找的數(shù)據(jù),答案可用下面代碼對拍。

參考代碼

#include<cstdio> #include<ctime> #include<iostream> using namespace std; char s[2000];int e_map[10][10],tot_x[10],max0=-1,tot=0; int tick_x[20],tick_y[20],tick_k[5][5],st_x,st_y; int max1(int p,int q) { return p>q?p:q; } int ed=0,lg[1025],went[10][10],goes[10]; void outputing() {for(int i=1;i<=9;i++)for(int j=1;j<=9;j++)printf("%d",e_map[i][j]);printf("\n"); } void output2() {for(int i=1;i<=9;i++){for(int j=1;j<=9;j++)printf("%d",e_map[i][j]);printf("\n"); }printf("\n"); } void output3(int k) {for(int i=1;i<=9;i++){printf("%d",k%2);k/=2;}printf("\n"); } int search() {for(int i=1;i<=9;i++){for(int k=goes[i];k>=1;k--){int j=went[i][k];st_x=i;st_y=j;goes[i]--;return i;//找到一個直接取位置就可以//后面會把goes再加回去}} } void dfs(int x,int y) {if(ed==1) return;if(tot==0){outputing();ed=1;return;}int ttt=tick_x[x]^511;//取反while(ttt){if(ed==1) return;int pk=ttt&-ttt;ttt-=pk;//lowbit取數(shù)if((pk&tick_y[y])) continue;if((pk&tick_k[(x+2)/3][(y+2)/3])) continue;//行、列、塊不沖突tick_x[x]|=pk;tick_y[y]|=pk;tick_k[(x+2)/3][(y+2)/3]|=pk;//短暫更新地圖(行列塊)的數(shù)據(jù)e_map[x][y]=lg[pk];tot--;int rst=search();dfs(st_x,st_y);//把取出來的數(shù)“放回去”,關(guān)鍵的一步剪枝goes[rst]++;tot++;tick_x[x]^=pk;tick_y[y]^=pk;tick_k[(x+2)/3][(y+2)/3]^=pk;//回溯需要還原e_map[x][y]=0;} } int main() {lg[1]=1;lg[2]=2;lg[4]=3;lg[8]=4;lg[16]=5;lg[32]=6;lg[64]=7;lg[128]=8;lg[256]=9;//為lowbit的計算做準備while(1){tot=ed=max0=0;scanf("%s",s);if(s[0]=='e') break;for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)tick_k[i][j]=0;//數(shù)組初始化for(int i=1;i<=9;i++){goes[i]=0;//每一行尾指針tick_x[i]=0;tick_y[i]=0;for(int j=1;j<=9;j++)went[i][j]=0;}for(int i=1;i<=9;i++)for(int j=1;j<=9;j++){if(s[(i-1)*9+j-1]=='.'){went[i][++goes[i]]=j;//記錄每一行合法位置e_map[i][j]=0;tot++;}else {//二進制壓縮e_map[i][j]=s[(i-1)*9+j-1]-'0';tick_x[i]|=(1<<(e_map[i][j]-1));tick_y[j]|=(1<<(e_map[i][j]-1));tick_k[(i+2)/3][(j+2)/3]|=(1<<(e_map[i][j]-1));}}//冒泡排序for(int i=1;i<=9;i++)for(int j=1;j<=9;j++)for(int k=1;k<=9;k++)if(went[i][j]>went[i][k]){int c=went[i][k];went[i][k]=went[i][j];went[i][j]=c;}search();//找出初始位置 // clock_t t; // t=clock();dfs(st_x,st_y); // t=clock()-t; // cout<<"時間為:"<<(((float)t)/CLOCKS_PER_SEC*1000)<<"ms\n"; //記錄dfs時間}return 0; }................................................................................. .2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534. ......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3. 1.3...5.9..21.94.....7.4...3..5.2..6.6.....5.7..8.3..4...4.1.....92.58..8.4...1.7 8..........36......7..9.2...5...7.......457.....1...3...1....68..85...1..9....4.. ..53.....8......2..7..1.5..4....53...1..7...6..32...8..6.5....9..4....3......97.. 98.7..6..7......8...6.5....4....3.....89...7.....2.3...1....2....75...6......1.54 .3...7..46.2.41....5..3.967.4...3..6.87...35.9..7...2.718.2..4....16.8.94..5...3. ..5..43.1..........28..6.4....4.5...7......6.6......3...3...17....1.9.....9..2..8 .6.....75....4..9.8.3........8.9.....72..6...6..4.5...12.6......3..7.2....7..431. ...8......3..92..1.9..3....7...498....57..9..2....6.....352.1...5....4.2..6..4... 43.28...............84...1.9.3..2.4..7..3..2..5.9..8.1.2...65...............41.76 57.12...............67...8.3.4..9.7..2..7..5..1.3..9.2.8...21...............54.63 ...6....7...849...28......5..7315....4..7......2......91..8..6.7......9...34..5.. 75..9..469.1...3.2.........2..6.1..7.8.....2.1..3.8..5.........3.9...2.484..3..79 end

總結(jié)

以上是生活随笔為你收集整理的2021 9.14 p.m.小结 以及 数独问题探索(T3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。