---
# System prepended metadata

title: 演算法 HW1
tags: [演算法]

---

# 演算法 HW1

## :book: 觀念題 

### 第一題 本週影片中提到的NP-complete問題有哪些？

* **NP-complete問題** : 此問題目前不存在一個有效率的解法。
* **有效率** : 在解決一個問題時，隨著問題增加，時間增長幅度不會太快。
* 常見的沒有效率的方法 : **暴力法**、**窮舉法**。
* 影片中提到的NP-complete問題 : 
    1. **0/1 Knapsack problem**
    將一群物品儘量塞進背包裡面，使背包裡面的物品總價值最高。背包有重量限制，如果物品太重。
        * 舉例(如下圖):
    假設背包能承受最大重量為14，則 P1,P2,P3,P5即為本題最佳解。
        * 方法:
    先找出每項物品單位價值，再由大到小裝入背包。(但背包可能會有多餘的空間)--不一定為最佳解。
    ![](https://i.imgur.com/tMkCgKl.png)

	2. **Traveling salesperson problem**
	給定一系列城市和每對城市之間的距離，求解訪問每一座城市一次並回到起始城市的最短迴路。
        * 舉例(如圖):
            ![](https://i.imgur.com/4fmwQ1g.png)
        * 方法:
            1. 每次找距離該點最近的點。--可能導致回程距離太大。
            2. 列出所有點的排序，並計算最短距離。
    3. **Partition problem**
    將已知的集合分成兩個子集，這兩個子集的元素分別總和是相等的，且兩子集的元素不得已重複，所有元素皆須用到。
        * 舉例:
        S={1,7,10,4,6,8,3,13},其解為
        S1={1,10,4,8,3}, S2={7,6,13}
        * 方法:
        先算出所有元素總和，再將結果除以2，再一一分群(列出所有可能)，直到分成兩群分別和等於此結果。
    
	4. **Art gallery problem** 
	給定一個藝廊的平面圖，我們要安排警衛的人數與位置使得警衛的人數要最少，但是藝廊裡的每一個角落都至少要有一個警衛能監視到。
        * 舉例(如圖):
            ![](https://i.imgur.com/nmXxW6d.png)
        * 方法:
        列舉法也無法解題，需使用特別的解題方式，如直接觀察。

### 第二題 請上網找一個老師沒說過的NP-complete問題，並舉個例子說明該問題的輸入與輸出。
**分團問題(clique problem)**
* 什麼是團(clique) ? 
就是 一個Graph，裡面 有一塊 是complete graph。
* 問一個圖中是否有大小是k以上的團?
* 任意挑出k個點，我們可以簡單的判斷出這k個點是不是一個團。
* 舉例(如下圖):
若k是3，而圖中1,2,5即為一個complete graph，我們就將其稱之為團(clique)。

  ![](https://i.imgur.com/k09Lyhq.png)

* **方法**
    1. 使用暴力法在V個點的圖中列舉k個點得子集合，並判斷是否為一個團。
    2. 先找出所有一個點的團，在進行合併。
    
##  :desktop_computer: 程式題 (使用語言 : C++)

### 示範題 改C++

* leetcode 704
* 時間:5分鐘
* 自己完成的程度：完全靠自己
* 程式碼:

```cpp==
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1,mid;
        int answer=-1;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(target==nums[mid])
            {
                answer=mid;
                break;
            }
            else if(target<nums[mid])
            {
                right=mid-1;
            }
            else
            {
                left=mid+1;
            }
        }
        return answer;
    }
};
```
* 通過截圖 :

    ![](https://i.imgur.com/c11WFYW.png)

### 第三題 二元搜尋應用：當數字可以重覆

* leetcode 704延伸
* 時間:10分鐘
* 自己完成的程度：完全靠自己
* 程式碼:

```cpp==
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1,mid;
        int answer=-1;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(target==nums[mid])
            {
                answer=mid;
                right=mid-1;
            }
            else if(target<nums[mid])
            {
                right=mid-1;
            }
            else
            {
                left=mid+1;
            }
        }
        return answer;
    }
};
```
* 通過截圖(為leetcode 704通過截圖)

    ![](https://i.imgur.com/iYz8rKc.jpg)
    
    ![](https://i.imgur.com/j8ZzmHD.png)


### 第四題 二元搜尋應用：找數字該插入的位置

* leetcode 35
* 時間:1小時
* 自己完成的程度：參考網路資料
* 程式碼:

```cpp==
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        int mid;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(target==nums[mid]) 
                return mid;
            else if(target<nums[mid]) 
                right=mid-1;
            else if(target>nums[mid]) 
                left=mid+1;
        }

        return left;
    }
};
```
* 通過截圖

    ![](https://i.imgur.com/vlXqfFq.jpg)

### 第五題 二元搜尋應用：找到最早出問題的版本

* leetcode 278
* 時間:1小時
* 自己完成的程度：靠自己
* 程式碼:

```cpp==
class Solution {
public:
    int firstBadVersion(int n) {
        int left=1;
        int right=n;
        int mid;
        int ans=-1;
        while(left<=right)
        {
            mid=left+(right-left)/2;
            if(isBadVersion(mid))
            {
                ans=mid;
                right=mid-1;
            }
            else if(!isBadVersion(mid))
            {
                left=mid+1;
            }
        }
        return ans;
    }
};
```
* 通過截圖

    ![](https://i.imgur.com/f4lAh2G.png)

### 第六題 二元搜尋應用：開根號後的整數部分

* leetcode 69
* 時間:2小時
* 自己完成的程度：自己coding完有錯，找不到bug，請同學幫忙並自己修正
* 程式碼:

```cpp==
class Solution {
public:
    int mySqrt(int x) {
        int mid=0;
        int num=-1;
        int ans=0;
        double middle=0.0;
        int left=0;
        int right=x;
        if(x<=1)
            return x;
        while(true)
        {
            middle=(left+right)/2;
            mid=middle;
            if(middle*middle==x || mid==num)
            {
                ans=mid;
                break;
            }
            else if(middle*middle<x)
            {
                left=middle+1;
                num=middle;
            }
            else if(middle*middle>x)
            {
                right=middle-1;
                num=middle;
            }
        }
        return ans;
    }
};
```
* 通過截圖

    ![](https://i.imgur.com/b0JuGbY.png)

## :pushpin:心得

### 第七題 本週心得

影片中老師講解得很仔細，之前就有聽過其中的NP-complete這個詞，但並不是很理解在做甚麼。看完影片後感覺有更了解了，也發現原來生活中很多看似簡單的問題，其實都屬於NP-complete。
作業由淺入深，從程式第一題開始理解二元搜尋怎麼用，到後面開根號的逼近也能用二元搜尋法解題，雖然後面題目寫得比較久，也思考得比較久，但覺得還行。

###### tags: `演算法`