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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

回溯算法题总结

發(fā)布時(shí)間:2025/3/17 编程问答 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 回溯算法题总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天筆試了華為的提前批,爆炸,三道題最后就拿了200分,各種輸入輸出問(wèn)題。。。醉了啊,題都不是很難,但輸入輸出折騰了半天T ?T。。。第三題是和尚挑水的問(wèn)題,

第二題就是找出數(shù)組中只能被自己整除的數(shù),思路也很簡(jiǎn)單,最水的方法就是對(duì)每一個(gè)數(shù),與數(shù)組中的其他數(shù)字進(jìn)行除法運(yùn)算,時(shí)間復(fù)雜度是O(n2)就不寫代碼了,也可以用通過(guò)維護(hù)一個(gè)除數(shù)的數(shù)組,具體時(shí)間復(fù)雜度有點(diǎn)難算,應(yīng)該是2nk,k是這個(gè)數(shù)組的長(zhǎng)度。代碼我稍微寫了一下。

#include <vector> #include <iostream>using namespace std;int main() {vector<int> nums{ 4,5};//即剔除只能本自己整除的數(shù)vector<int> temp{ 4 };int flag = true;for (int i = 0; i < nums.size(); i++) {for (auto iter = temp.begin(); iter != temp.end(); iter++) {if (*iter%nums[i] == 0) {*iter = nums[i];flag = false;break;}else if (nums[i] % (*iter) == 0) {flag = false;break;}}if (flag) {temp.push_back(nums[i]);}else {flag = true;}}for (auto m : temp) {cout << m << " ";} }

  


一、問(wèn)題
某寺廟里7個(gè)和尚:輪流挑水,為了和其他任務(wù)不能沖突,各人將有空天數(shù)列出如下表:
和尚1: 星期二,四;
和尚2: 星期一,六;
和尚3: 星期三,日;
和尚4: 星期五;
和尚5: 星期一,四,六;
和尚6: 星期二,五;
和尚7: 星期三,六,日;
請(qǐng)將所有合理的挑水時(shí)間安排表

其實(shí)思路很簡(jiǎn)單,就是使用回溯算法,但是我自己太坑了啊,當(dāng)時(shí)看到八皇后的題時(shí)候,知道用回溯算法,但是就看了一眼,沒(méi)自己動(dòng)手實(shí)現(xiàn),結(jié)果今天不會(huì)寫回溯。。。哈哈哈哈哈,最后用了非常傻逼的方法,就是全排列以后然后再選擇符合的答案輸出,但是格式有問(wèn)題。。。最后300就拿了100分 ?_(:з」∠)____ 23333,對(duì)了,第二題我更加傻逼,200分一分沒(méi)拿,哈哈哈哈哈氣哭了,還是因?yàn)檩斎雴?wèn)題。。。。。感覺(jué)要好好練一下輸入輸出啊。。。

今天通過(guò)這題把回溯算法總結(jié)一下吧。

?這邊先上我用非回溯寫的算法,首先全排列,然后判斷即可。

代碼

#include <iostream> #include <vector>using namespace std;void allCombination( vector<int> &nums, vector<vector<int>> &res, int start){if( start == 7 ){res.push_back(nums);return;}for( int i = start; i < 7; i++ ){swap(nums[i],nums[start]);allCombination(nums,res,start+1);swap(nums[i],nums[start]);} }int main(){ // vector<vector<int>> source(7,vector<int>(7,0)); // for( int i = 0; i < 7; i++ ){ // for( int j = 0; j < 7; j++ ){ // cin>>source[i][j]; // } // }vector<vector<int>> source{{0,1,0,1,0,0,0},{1,0,0,0,0,1,0},{0,0,1,0,0,0,1},{0,0,0,0,1,0,0},{1,0,0,1,0,1,0},{0,1,0,0,1,0,0,},{0,0,1,0,0,1,1}};int count = 0;vector<int> nums{1,2,3,4,5,6,7};vector<vector<int>> res;allCombination(nums, res, 0);vector<vector<int>> resoult;bool flag = true;for( int i = 0; i < res.size(); i++ ){for( int j = 0; j < 7; j++ ){if(source[res[i][j]-1][j] == 0 ){flag = false;break;}}if( flag ){resoult.push_back(res[i]);count++;}else{flag = true;}}cout<<count<<endl;for( int i = 0; i < resoult.size(); i++ ){for( int j = 0; j < 7; j++ ){cout<<resoult[i][j]<<" ";}cout<<endl;} }

那全排列的問(wèn)題是什么?其實(shí)就是減枝的問(wèn)題,在排列的時(shí)候沒(méi)有直接將不可能的結(jié)果去掉,比如1,X,X,X,X,X,X這樣的排列組合,如果第一個(gè)和尚規(guī)定第一天就不能抬水,那么所有1開(kāi)頭的組合方式都是沒(méi)有必要去驗(yàn)證的。所以回溯算法的本質(zhì)其實(shí)是在可能的解空間進(jìn)行搜索,這樣相對(duì)于枚舉的優(yōu)勢(shì)就是能夠更快的找到解。

如果有了這樣的的思路,那我們就可以這樣判斷從第一天開(kāi)始判斷,往后進(jìn)行判斷,如果當(dāng)天某一個(gè)和尚能夠挑水,則放入解向量中,并把這個(gè)和尚的標(biāo)志設(shè)為已經(jīng)挑水,如果往下搜索以后,發(fā)現(xiàn)所有情況都不能滿足了,則回退到上一步,換其他的和尚挑水,反復(fù)進(jìn)行,直到所有可能情況都遍歷。

這邊需要注意的一個(gè)是截止條件,比如對(duì)于和尚挑水這一題,

1.截止條件應(yīng)該就是第一天挑水的和尚為不存在的第八個(gè)和尚,即<8。

2.是一個(gè)成功解的判定條件是解向量的長(zhǎng)度為7,即每一天都有和尚挑水。

3.如果當(dāng)前這一天成功,則搜尋下一天,如果當(dāng)天失敗,則回退到上一天。對(duì)3過(guò)程進(jìn)行迭代

#include <iostream> #include <vector>using namespace std;void allPossibleResult( vector<int> &isSelected, int day, vector<vector<int>> &source, vector<int> res ){if( day == 7 ){for( int i = 0 ; i < 7; i++ ){cout<<res[i]<<" ";}cout<<endl;return; }else{for( int i = 0; i < 7; i++ ){res[day] = i+1; //第day天選擇第i個(gè)和尚挑水if( source[i][day] == 1 && isSelected[i] != 1 ){isSelected[i] = 1;allPossibleResult(isSelected, day+1, source, res);isSelected[i] = 0;} }} }int main(){// vector<vector<int>> source(7,vector<int>(7,0)); // for( int i = 0; i < 7; i++ ){ // for( int j = 0; j < 7; j++ ){ // cin>>source[i][j]; // } // }vector<vector<int>> source{{0,1,0,1,0,0,0},{1,0,0,0,0,1,0},{0,0,1,0,0,0,1},{0,0,0,0,1,0,0},{1,0,0,1,0,1,0},{0,1,0,0,1,0,0,},{0,0,1,0,0,1,1}};vector<int> isSelected(7,0);vector<int> res(7,0);int num = 0;int day = 0;allPossibleResult(isSelected, day, source, res); }

試著用回溯法解一下把皇后

其實(shí)八皇后最大的不同應(yīng)該就是if判斷語(yǔ)句不同,如何判斷與這邊不同。

我設(shè)置了一個(gè)判斷函數(shù),判斷的過(guò)程就是判斷行上是否有皇后存在,判斷列上是否有皇后存在,然后判斷對(duì)角線,這邊比較麻煩的是對(duì)角線,其實(shí)對(duì)角線可以這么判斷,對(duì)于坐標(biāo)(a,b),如果對(duì)于點(diǎn)(c,d) a-c == b - d或者 a-c == d-b那么他們就是在一條對(duì)角線上,這樣就能夠判斷所有行列和對(duì)角線了。其實(shí)感覺(jué)這個(gè)方法不怎么好,判斷起來(lái)太復(fù)雜了。網(wǎng)上貌似提到了位操作的方法,可以思考下。

代碼如下。

#include <iostream> #include <vector>using namespace std;bool isCheck(vector<vector<int>> matrix, int index, int i) {bool flag = true;for (int j = 0; j < 8; j++) {if (matrix[j][index] == 1 || matrix[i][j] == 1) {flag = false;break;}for (int k = 0; k < 8; k++) {if ((j - i == k - index || j - i == index - k) && j != i && k != index ) {if( matrix[j][k] == 1 )flag = false;}}}return flag; }void EightQueen(vector<int> &res, vector<vector<int>> &matrix, int &count, int index) {if (index == 8) {for (auto m : res) {cout << m << " ";}cout << endl;count++;return;}for (int i = 0; i < 8; i++) {res[index] = i;if (isCheck(matrix, index,i)) {matrix[i][index] = 1;EightQueen(res, matrix, count, index + 1);matrix[i][index] = 0;}}}int main() {int sum = 0;vector<int> res(8, 0);vector<vector<int>> matrix(8, vector<int>(8, 0));int count = 0;EightQueen(res, matrix, count, 0);cout << count << endl; }

我這邊是通過(guò)一個(gè)一維數(shù)組輸出的,比如{0,4,7,5,2,6,1,3}表示第一列的第1行放皇后,第二列的第4行放皇后,第三列的第7行放皇后.....

?

轉(zhuǎn)載于:https://www.cnblogs.com/rockwall/p/5778414.html

總結(jié)

以上是生活随笔為你收集整理的回溯算法题总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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