前言
學到演算法這邊終於知道題目不是能解出來就好,要解的簡潔,什麼意思呢?就是說不是答案對就可以了,要有效率,執行速度能快就快,使用空間能小就小,這樣的觀念打破我一直以來的想法,也對程式越來越有興趣了,程式啊程式,你是多麼神秘且講道理啊!!!!
## 貪婪演算法
貪婪演算法就是做眼前最佳的動作,也就是局部解,但是到最後不見得是最好的動作,以下舉一個找零錢的例子。
通常找顧客零錢都是先將面額大的給顧客,再將較第二大的面額給顧客,依序這樣下去,直到不能找為止,所以貪婪演算法就是運用這個想法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
int main(){
int cash[10],n;
cash[0] = 1;
cash[1] = 5;
cash[2] = 10;
cash[3] = 50;
cash[4] = 100;
cash[5] = 500;
cash[6] = 1000;
cin >> n;
cout << n << "=";
for(int i = 6;i >= 0;i--){
if(n >= cash[i]){
cout << cash[i] << "*" << n/cash[i] << " ";
n = n%cash[i];
}
}
return 0;
}
貪婪演算法-最小生成樹(Minimum spanning trees)MST
其實tree是一種資料結構,但我配合greedy來講。
Tree的特性,必連通,但不能有cycle。
MST的定義就是生成出來的樹,他的邊的總和最小的。
英文版定義(由於翻譯成中文可能無法清楚表達他的含義,所以這邊使用別人的定義,原文是英文):
Definition: G = (V,E):weighted connected undirected graph * Spanning tree : S = (V,T),T ⊆ E,undirected
tree * Minimum spanning tree(MST) : a
spanning tree with the smallest total weight. 中文定義: 1.
樹(tree):一個無向連通非環狀圖(acyclic,connected, undirected graph) 2.
有根樹(rooted
tree):以某個頂點為跟的樹(獨立於樹之外的頂點不能作為根)。因此有根樹也被直接稱為樹。
3. 生成樹(spanning tree):包含圖中所有頂點且符合樹的定義的連通子圖。 4.
最小生成樹(minimum spanning tree):即具有最小的權重的生成樹。 ##
用貪婪演算法解最小生成樹 1
2
3
4
5
6
7
8F = empty set
while(當問題未得解){
找出問題區域最佳解的方式找出一個邊;
if(選出來的邊不會使F產生任何cycle)
將邊加入F中;
if(答案是生成樹)
此問題得解;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using namespace std;
int main(){
int counts;
while(cin >> counts){
vector<int> vec;
int temp;
for(int i = 0;i < counts;i++){
cin >> temp;
vec.push_back(temp);
}
for(int i = 0;i < counts;i++){
for(int k = 0;k < counts-1;k++){
if(vec[k] > vec[k+1])
swap(vec[k],vec[k+1]);
}
}
for(int i = 0 ;i < counts;i++){
cout << vec[i] << " ";
}
cout << endl;
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using namespace std;
long long int infinity = 999999999;
void merge(vector<int> &vec,int first,int mid,int last){
vector<int> left_area(vec.begin()+first,vec.begin()+mid+1);
vector<int> right_area(vec.begin()+mid+1,vec.begin()+last+1);
left_area.emplace(left_area.end(),infinity);
right_area.emplace(right_area.end(),infinity);
int left_idx = 0,right_idx = 0;
for(int i = first;i <= last;i++){
if(left_area[left_idx] <= right_area[right_idx]){
vec[i] = left_area[left_idx];
left_idx++;
}
else{
vec[i] = right_area[right_idx];
right_idx++;
}
}
}
void merge_sort(vector<int> &vec,int first,int last){
if(first < last){
int mid = (first+last)/2;
merge_sort(vec,first,mid);
merge_sort(vec,mid+1,last);
merge(vec,first,mid,last);
}
}
int main(){
vector<int> vec{48,23,19,34,65,20,3};
cout << "original : ";
for(int i = 0;i < vec.size();i++)
cout << vec[i] << " ";
cout << endl;
cout << "After merge sort : ";
merge_sort(vec,0,7);
for(int i = 0;i < vec.size();i++)
cout << vec[i] << " ";
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using namespace std;
struct data{
int a;
int b;
};
bool cmp(data x,data y){
if(x.a == y.a) return x.b < y.b;
else return -1;
}
int main(){
data foo[10];
srand(time(NULL));
for(int j = 0;j < 10;j++)
foo[j].a = 0;
for(int i = 0;i < 10;i++){
foo[i].b = rand()%1000;
}
sort(foo,foo+10,cmp);//此處加入第三個參數
for(int i = 0;i < 10;i++)
cout << foo[i].b << " ";
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using namespace std;
void quick_sort(int *arr,int front_,int end_);
void swap_(int *a,int *b);
int partition_(int *arr,int front_,int end_);
int main(){
int arr[10] = {3,5,7,2,13,21,6,1};
for(int i = 0;i < 8;i++)
cout << arr[i] << " ";
cout << endl;
quick_sort(arr,0,7);
for(int i = 0;i < 8;i++)
cout << arr[i] << " ";
return 0;
}
void swap_(int *a,int *b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void quick_sort(int *arr,int front_,int end_){
if(front_ < end_){
int pivot = partition_(arr,front_,end_);
quick_sort(arr,pivot+1,end_);
quick_sort(arr,front_,pivot-1);
}
}
int partition_(int *arr,int front_,int end_){
int pivot = arr[end_];
int i = front_-1;
for(int j = front_;j < end_;j++){
if(arr[j] < pivot){//to control ascending power and Descending powers
i++;
swap_(&arr[i],&arr[j]);
}
}
i++;
swap_(&arr[i],&arr[end_]);
return i;
}
總結
我覺得排序演算法是一堂很重要的課,也是進入演算法世界的第一把鑰匙,表面上在排序,但實際上有許多的觀念在背後,其實排序演算法有很多,但我這邊就舉三個例子即可,學玩排序後就來學搜尋吧!
## 二分搜尋法(binary search)
配合圖片二分搜會學的比較輕鬆,在進行二分搜前可以先畫一個\(1\) * \(n\)的矩陣來幫助理解 以上為一個\(1\)*\(9\)的矩陣,每個格子中儲存一個數字,切記在進行二分搜得時候要先把數字排好,我習慣由小排到大,而接下來就可以進行搜尋了。
假設我們要搜尋的目標是14
我們先將矩陣的數量除二,可得目前index值為(0+8)/2
= 4,而index[4]的位置並非我們要找的數值,且index[4] =
9小於我們的目標14所以我們直接拋棄尋找小於9的數字,直接往以9為中心的右側繼續尋找下一個,一直重複此動作即可尋找到14
的位置。
我們之所以要使用binary search 而不用linear search是因為linear search的time complexity 是O(n) 而binary search 的 time complexity 是O(logn)比較快。
程式碼: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using namespace std;
int Binary_search(int * arr,const int target,int left,int right);
int main(){
int arr[10] = {3,19,23,8,14,6,9,1,20};//1,3,6,8,9,14,19,20,23
const int target = 14;
sort(arr,arr+9);
int position = Binary_search(arr,target,0,8);
cout << position+1 << endl;
return 0;
}
int Binary_search(int * arr,const int target,int left,int right){
while(left < right){
int mid = (left+right)/2;
if(arr[mid] == target) return mid;
else if(arr[mid] > target) right = mid;
else if(arr[mid] < target) left = mid+1;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using namespace std;
int vertex,edge;
bool visited[10] = {false};
int maps[10][10] = {{0}};
void dfs(int node);
void print();
int main(){
cin >> vertex >> edge;
int tmp1,tmp2;
for(int i = 0;i < edge;i++){
cin >> tmp1 >> tmp2;
maps[tmp1-1][tmp2-1] = maps[tmp2-1][tmp1-1] = 1;
}
print();
cout << endl;
for(int i = 0;i < vertex;i++){
if(!visited[i]) dfs(i);
}
return 0;
}
void dfs(int node){
cout << node+1 << " ";
visited[node] = true;
for(int i = 0;i < edge;i++){
if(!visited[i] && maps[node][i] == 1) dfs(i);
}
}
void print(){
for(int i = 0;i < vertex;i++){
for(int j = 0;j < vertex;j++){
cout << maps[i][j] << " ";
}
cout << endl;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using namespace std;
int graph[N][M];
int visited[N];
void dfs(int n);
int main(){
fill(visited,visited+N,0);
int n,m;
cin >> n >> m;
int tmp1,tmp2;
for(int i = 0;i < n;i++){
cin >> tmp1 >> tmp2;
graph[tmp1][tmp2] = 1;
graph[tmp2][tmp1] = 1;
}
cout << endl;
visited[1] = 1;
dfs(1);
return 0;
}
void dfs(int n){
cout << n << " ";
for(int i = 1;i <= 6;i++){
if(graph[n][i] == 1 && visited[i] == 0){
visited[i] = 1;
dfs(i);
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using namespace std;
bool visited[vertex];
int line[edge][2];
void bfs(int n){
int que[100];
visited[n] = true;
int last = -1,first = -1;
que[++last] = n;
while(first < last){
int pop = que[++first];
cout << pop << " ";
for(int i = 0;i < vertex;i++){
if(visited[i] == 0 && line[pop][i] == 1){
que[++last] = i;
visited[i] = true;
}
}
}
}
int main(){
fill(visited,visited+vertex,0);
memset(line,0,sizeof(line));
for(int i = 0;i < edge;i++){
int tmp1,tmp2;
cin >> tmp1 >> tmp2;
line[tmp1][tmp2] = line[tmp2][tmp1] = 1;
}
for(int i = 0;i < vertex;i++){
if(!visited[i]){
bfs(i);
}
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
using namespace std;
int f(int n){
if(n == 1 || n == 2) return 1;
return f(n-1)+f(n-2);
}
int main(){
for(int i = 1;i <= 10;i++){
cout << f(i) << " ";
}
cout << endl;
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
using namespace std;
int main(){
long long int f[100];
f[0] = 1;
f[1] = 1;
for(int i = 2;i < 80;i++)
f[i] = f[i-1]+f[i-2];
cout << f[69] << endl;//ouput = 190392490709135
return 0;
}