---
# System prepended metadata

title: 二上進階程式設計實習學期總結

---

二上進階程式設計實習學期總結
===
序言
---
 這是在二上的時候，實習課的程式實際操作，而我將其中幾個程式統整起來，當作一個紀錄。

程式的主題
---

### 1.最接近的高人:
題意:

>對於一個人來說，只要比他高的人就是高人。有 N
個人排成一列，對於每一個人，要找出排在他前方離他最近的高人，排在之後的高人不算，假設任兩個相鄰的人的距離都是
1，本題要計算每個人和他前方最近高人的距離之總和。如果這個人前方沒有高人(前方沒人比他高)，距離以他的位置計算(等價於假設最前方有個無窮高的高人)。
日期:2022.11.22

程式碼:
```cpp!
#include <bits/stdc++.h>
using namespace std;
#define N 300010
#define oo 10000001
int a[N];
stack<int> S;
int main() {
  int i, n;
  long long total = 0; // total distance
  scanf("%d", &n);
  S.push(0);
  a[0] = oo;
  for (i = 1; i <= n; i++) {
    scanf("%d", &a[i]);
  }
  cout << "每個位置，與前面高人的距離:\n";
  for (i = 1; i <= n; i++) {

    int cnt = i; //陣列的位置

    while (a[S.top()] <= a[i]) {

      S.pop();
    }
    cnt -= S.top(); //陣列的位置減去堆疊頂端即為距離
    total += i - S.top();
    S.push(i);
    cout << "(" << i << "): " << cnt << "\n";
  }
  printf("總距離 = %lld\n", total);
  return 0;
}
```

執行結果:
![](https://i.imgur.com/MoHEnCS.png)

新增功能:
***除了列印出最高的高人，還有列出每個人的高人。***

---
### 2.定長度區間的最大區段差
題意:

>固定長度區間的最大區段差
對於序列的一個連續區段來說，區段差是指區段內的最大值減去區段內的最小值。有N
個非負整數組成的序列 seq，請計算在所有長度為 L 的連續區段中，最大的區段差為何。
date:2022.12.20

程式碼:
```cpp!
#include <bits/stdc++.h>
using namespace std;
#define MAXN 200010
int seq[MAXN];
deque<int> max_q, min_q; // index of max and min queue
// put seq[i] from back of max_q
int max_n = 0, min_n = 0;
void put_max(int i) {
  // remove useless
  while (!max_q.empty() && seq[max_q.back()] <= seq[i])
    max_q.pop_back();
  max_q.push_back(i);
}
// put seq[i] from back of min_q
void put_min(int i) {
  // remove useless
  while (!min_q.empty() && seq[min_q.back()] >= seq[i])
    min_q.pop_back();
  min_q.push_back(i);
}
int main() {
  int n, L, i, j, max_diff = 0;
  scanf("%d%d\n", &n, &L);
  for (i = 0; i < n; i++) {
    scanf("%d", &seq[i]);
  }
  put_max(0);
  put_min(0);
  for (i = 1; i < n; i++) {
    // put the ith element into max_queue
    if (max_q.front() <= i - L) // out-of-range
      max_q.pop_front();        // its index

    put_max(i);
    max_n = max_q.front(); //取得最大值的首位index
    // put the ith element into min_queue
    if (min_q.front() <= i - L) // out of range
      min_q.pop_front();
    put_min(i);
    min_n = min_q.front(); // 取得最小值的index
    // the diff of this subarray
    int diff = seq[max_q.front()] - seq[min_q.front()];
    max_diff = max(max_diff, diff);
  }

  cout << "差值最大的區段為 [ ";
  for (int i = max_n; i < max_n + 4; i++) {
    cout << seq[i] << " "; //輸出取得的區間值
  }
  cout << "]";
  cout << "\n區段最大值 = " //最大值第一位
       << seq[max_n] << "\n";
  cout << "區段最小值 = " //最小值
       << seq[min_n] << "\n";
  printf("最大差值為 = %d\n", max_diff);
  return 0;
}
```
執行結果:
![](https://i.imgur.com/GYstaWx.png)

新增功能:
***除了找出最大的區段差，還有列出最大值最小值及最大區段。***

---
### 3.最多色彩帶
題意:

>有一條細長的彩帶，彩帶區分成 n
格，每一格的長度都是 1，每一格都有一個顏色，相鄰可能同色。給定長度限制
L，請找出此彩帶長度 L 的連續區段最多可能有多少種顏色。 data:2022.12.27

程式碼:
```cpp!
#include <bits/stdc++.h>
using namespace std;
#define N 200010
int seq[N], cnt[N] = {0}; // counter of color i
int t_cnt;
int main() {
  int n, L, i;
  scanf("%d%d", &n, &L);
  int n_color = 0;
  for (i = 0; i < n; i++)
    scanf("%d", &seq[i]);
  // initial window
  for (i = 0; i < L; i++) {
    int color = seq[i];
    cnt[color]++;
    if (cnt[color] == 1)
      n_color++;
  }
  int ans = n_color, left;

  // sliding window, seq[i] in, seq[left] out
  for (left = 0, i = L; i < n; i++, left++) {
    int color = seq[i];
    cnt[color]++;
    if (cnt[color] == 1) {
      n_color++;
    }
    color = seq[left];
    cnt[color]--;
    if (cnt[color] == 0) {
      n_color--;
    }
    if (n_color > ans) { //如果有新的最大值
      ans = n_color;
      t_cnt = left + 1; //就記錄下他的首位
    }
  }
  cout << "\n色彩種類最多序列: ";
  for (int i = 0; i < L; i++) {
    cout << seq[t_cnt + i] << " "; //將從首位的值依序輸出
  }
  cout << "\n";
  printf("最多色彩共 %d 種\n", ans); //輸出最多顏色區段
  return 0;
}

```
執行結果:
![](https://i.imgur.com/61EO4kT.png)

新增功能:
***找出顏色種類最多的序列***

---
### 4.樹狀圖分析
題意:

>有一個大家族有 N 個成員，編號
1~N，我們請每個成員寫下此家族中哪幾位是他的孩子。我們要計算每個人有幾代的子孫，這個值稱為他在這個族譜中的高度，也就是說，編號 i 的人如果高度記做
h(i)，那麼 h(i)就表示在所有 i 的子孫中，最遠的子孫與他隔了幾代。本題假設除了最高的一位祖先(稱為 root)之外，其他成員的 parent
都在此家族中(且只有一個 parent)。本題要計算所有成員高度的總和以及根的編號


程式碼:
```cpp!
#include <bits/stdc++.h>
using namespace std;
#define N 100
void showTree(vector<int> V[], int n);
int findRoot(int parent[], int n);
void bfs(vector<int> V[], int root);
int main() {
  vector<int> V[N];

  int parent[N] = {0};
  int h[N] = {0};    // 記錄每個節點的高度
  int n, childCount; // n:節點數量   childCount:子節點的數量
  int root;

  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> childCount;
    for (int j = 0; j < childCount; j++) {
      int child; // child:子節點
      cin >> child;
      V[i].push_back(child);
      parent[child] = i;
    }
  }
  showTree(V, n);
  root = findRoot(parent, n);
  cout << "\n root=" << root << "\n";
  long long step = 0;
  for (int i = 1; i <= n; i++) { //每個節點
    int cnt = 0;                 // i走的步數
    // 直到走到root為止
    for (int j = i; j != 0; j = parent[j]) {
      h[j] = max(h[j], cnt);
      cnt++;
      step++;
    }
  }

  long long total = 0;
  for (int i = 1; i <= n; i++)
    total += h[i];
  printf(" high:%lld\n", total);

  bfs(V, root); //廣度搜尋

  return 0;
}
int findRoot(int parent[], int n) {
  int root;
  for (root = 1; root <= n; root++) { //找根
    if (parent[root] == 0)
      break;
  }

  return root;
}
void showTree(vector<int> V[], int n) { //列出樹狀結構
  // cout << "\n\nVector :\n" ;
  for (int i = 1; i <= n; i++) {
    printf(" node [ %d ]", i);
    // if( V[i].size()==0)printf("  ->  X");
    for (int j = 0; j < V[i].size(); j++) {
      printf("  -> %d ", V[i][j]);
    }
    printf("\n");
  }
}

void bfs(vector<int> V[], int root) {
  queue<int> q;
  vector<bool> vi;     //走訪標記
  vi.assign(N, false); //走訪標記
  q.push(root);        //設定出初始位置
  vi[root] = true;
  cout << " BFS check order:";

  while (!q.empty()) {

    int f = q.front();
    q.pop();

    cout << "->" << f; //輸出當前節點

    for (auto i = V[f].begin(); i != V[f].end(); i++) { //鄰近節點
      if (!vi[*i]) {
        q.push(*i);

        vi[*i] = true;
      }
    }
  }
  cout << "\n";
}


```
執行結果:
![](https://i.imgur.com/NH23JIX.png)
![](https://i.imgur.com/PjYnoPv.png)


新增功能:
***顯示搜尋過程及全部節點的高度總和***

---