# 演算法作業01 ## 1. 本週影片中提到的NP-complete問題有哪些? 1. 0/1有限背包問題 2. 旅行商問題 3. 分區問題 4. 畫廊監視器問題 ## 2. 請上網找一個老師沒說過的NP-complete問題,並舉個例子說明該問題的輸入與輸出。 最簡單的就是N皇后了 在$N \times N$的西洋棋棋盤上放上$N$個皇后棋, 並且要放置在讓它們不會互相攻擊到的位置上,問有幾種擺放方式。 最常見的是$N=8$,也就是8皇后問題。 ![image](https://hackmd.io/_uploads/SyCHjau2T.png) ###### 圖片來源:https://medium.com/@jamesjessian/solving-the-n-queens-completion-puzzle-ed8924ce8f1c ### 相關NP-complete證明 https://www-users.york.ac.uk/peter.nightingale/IJCAI2018-nQueens.pdf 下面是我寫的範例程式: ```cpp= #include <bits/stdc++.h> using namespace std; int queen[20],sum,N; void dfs(int row) { if(row == N) { sum++; return; } int i,j; for(i=1;i<=N;i++) { for(j=0;j<row;j++) { if(queen[j]==i || abs(queen[j]-i)==row-j) { break; } } if(j==row) { queen[row]=i; dfs(row+1); queen[row]=0; } } } int main() { sum=0; cin>>N; dfs(0); cout<<sum; } ``` 輸入是$N$,代表棋盤邊長以及皇后數量, 輸出是可擺放的方式數量。 如果N=8 輸出會是92 因為有92種擺法 ## 3. 二元搜尋應用:當數字可以重覆 ### 1. 解題思路 把等於也認定為上界之外, 最後找到的 $l$ 就會是答案。 ### 2. 程式碼 ```cpp= #include <bits/stdc++.h> using namespace std; int search(vector<int>& nums, int target) { int mid,l=0,r=nums.size()-1; while(l<=r) { mid=(l+r)/2; if(nums[mid]>=target) { r=mid-1; } else { l=mid+1; } } return ((nums[l]==target)?l:-1); } int main() { vector<int> v={1,3,3,6}; cout<<search(v,3)<<endl; cout<<search(v,2)<<endl; v={1,2,3,6,6,6,7,8,9}; cout<<search(v,6); } ``` ### 3. 測試輸出輸入的畫面截圖 ![image](https://hackmd.io/_uploads/rJbnRWUna.png) ### 4. 花費時間 15分鐘 ### 5. 完成程度 完全自己解出 ## 4. 二元搜尋應用:找數字該插入的位置 ### 1. 解題思路 把3.的程式最後return的地方改成回傳$l$就可以了, 因為如果要插入的話也是要插入在第一個比他大的那個索引值。 ### 2. 程式碼 ```cpp= class Solution { public: int searchInsert(vector<int>& nums, int target) { int mid,l=0,r=nums.size()-1; while(l<=r) { mid=(l+r)/2; if(nums[mid]>=target) { r=mid-1; } else { l=mid+1; } } return l; } }; ``` ### 3. 測試輸出輸入的畫面截圖 ![image](https://hackmd.io/_uploads/Sk8p-zUh6.png) ### 4. 花費時間 2分鐘 ### 5. 完成程度 完全自己解出 ## 5. 二元搜尋應用:找到最早出問題的版本 ### 1. 解題思路 在4.的基礎上把判斷條件改成是否為壞版本, 然後把$(l+r)/2$改成$(l+(r-l)/2)$,防止int溢位(私心不想用long long) ### 2. 程式碼 ```cpp= // The API isBadVersion is defined for you. // bool isBadVersion(int version); class Solution { public: int firstBadVersion(int n) { int mid,l=0,r=n; while(l<=r) { mid=l+(r-l)/2; if(isBadVersion(mid)) { r=mid-1; } else { l=mid+1; } } return l; } }; ``` ### 3. 測試輸出輸入的畫面截圖 ![image](https://hackmd.io/_uploads/r1hUmGL2p.png) ### 4. 花費時間 6分鐘 ### 5. 完成程度 完全自己解出 ## 6. 二元搜尋應用:開根號後的整數部分 ### 1. 解題思路 找到第一個大於解的數,然後再減一即可。 (超過份這題逼我用long long,討厭鬼) ### 2. 程式碼 ```cpp= class Solution { public: int mySqrt(int x) { long long l=1,r=x,mid; while(l<=r) { mid=l+(r-l)/2; if(mid*mid>x) { r=mid-1; } else { l=mid+1; } } return l-1; } }; ``` ### 3. 測試輸出輸入的畫面截圖 ![image](https://hackmd.io/_uploads/HyxOrMUn6.png) ### 4. 花費時間 5分鐘 ### 5. 完成程度 完全自己解出 ## 7. 本週心得 ### 已填