[土狗之路]coursera上C++基礎第10周作業(下)
程式設計題#5:異常細胞檢測
來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。)
注意: 總時間限制: 1000ms 記憶體限制: 65536kB
描述
我們拍攝的一張CT照片用一個二維陣列來儲存,假設陣列中的每個點代表一個細胞。每個細胞的顏色用0到255之間(包括0和255)的一個整數表示。我們定義一個細胞是異常細胞,如果這個細胞的顏色值比它上下左右4個細胞的顏色值都小50以上(包括50)。陣列邊緣上的細胞我們不檢測。現在我們的任務是,給定一個儲存CT照片的二維陣列,寫程式統計照片中異常細胞的數目。
輸入
第一行包含一個整數N(100>=N>2).
下面有 N 行,每行有 N 個0~255之間的整數,整數之間用空格隔開。
輸出
輸出只有一行,包含一個整數,為異常細胞的數目。
樣例輸入
4 70 70 70 70 70 10 70 70 70 70 20 70 70 70 70 70
樣例輸出
2
#include<iostream> using namespace std; int main() { int n; int count=0; cin >> n; cin.get(); int numbers[100][100]; for (int i = 0; i < n; i++) { for (int j = 0; j <n;j++){ cin >> numbers[i][j]; } } for (int i = 0; i < n; i++) { if (i == 0 || i == n - 1) continue;//如果是邊上的,直接跳過就好了 else { for (int j = 0; j < n; j++) { if (j == 0 || j == n - 1) continue; else if (((numbers[i + 1][j] - numbers[i][j] >= 50) && (numbers[i][j + 1] - numbers[i][j] >= 50) && (numbers[i - 1][j] - numbers[i][j] >= 50) && (numbers[i][j - 1] - numbers[i][j] >= 50)) == true) {//&&的話,幾種條件都滿足,才會返回true count++; } } } } cout << count << endl; return 0; }
程式設計題#6:迴圈移動
來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。)
注意: 總時間限制: 1000ms 記憶體限制: 65536kB
描述
給定一組整數,要求利用陣列把這組數儲存起來,再利用實現對陣列中的數迴圈移動。假定共有n個整數,則要使前面各數順序向後移m個位置,並使最後m各數變為最前面的m各數。
注意,不要用先輸出後m個數,再輸出前n-m個數的方法實現,也不要用兩個陣列的方式實現。
要求只用一個數組的方式實現,一定要保證在輸出結果時,輸出的順序和陣列中數的順序是一致的。
輸入
輸入有兩行:第一行包含一個正整數n和一個正整數m,第二行包含n個正整數。每兩個正整數中間用一個空格分開。
輸出
輸出有一行:經過迴圈移動後陣列中整數的順序依次輸出,每兩個整數之間用空格分隔。
樣例輸入
11 4 15 3 76 67 84 87 13 67 45 34 45
樣例輸出
67 45 34 45 15 3 76 67 84 87 13
提示
這是一道經典的演算法問題,在企業面試裡出現概率很高。除了迴圈m次每次移動一個數以外(這樣需要對陣列操作m*n次),你還能想到更高效的演算法嗎(只用操作3*n次)?依然要求不使用額外陣列,在原陣列上移位之後順序輸出。
這個題先來我自己最原始的做法:#include<iostream>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int number[500];
for (int i = 0; i < n; i++) {
cin >> number[i];
}
for (int i = 0; i < m; i++) {
int temp = number[0];
int temp1 = number[1];
int temp2 = number[n - 1];
for (int j = 1; j < n; ) {
temp1 = number[j];
number[j] = temp;
temp = temp1;
j++;
}
number[0] = temp2;
}
for (int i = 0; i < n; i++) {
if (i != n - 1)
cout << number[i] << ' ';
else
cout << number[i] << endl;
}
return 0;
}
然後說一下聽了別人講解之後自己寫的,說實在的,到現在我都不知道這是怎麼推倒出來的,而只是知道怎麼去做
#include<iostream>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int number[500];
for (int i = 0; i < n; i++) {
cin >> number[i];
}
int j = 0;
for (int i = n - m; i < n - m / 2; i++) {//將陣列後m值倒序
int temp = number[i];
number[i] = number[n - 1 - j];
number[n - j - 1] = temp;
j++;
}
int k = 0;
for (int i = 0; i < (n-m)/2; i++) {//將陣列前n-m的值倒序
int temp = number[i];
number[i] = number[n-m-k-1];
number[n -m- k - 1] = temp;
k++;
}
for (int i = 0; i < n/2; i++) {//最後將整個陣列倒序
int temp = number[i];
number[i] = number[n - 1 - i];
number[n - i-1] = temp;
}
for (int i = 0; i < n; i++) {
if(i!=n-1)
cout<< number[i]<<' ';
if (i == n - 1)
cout << number[i] << endl;
}
return 0;
}
在這裡說下自己的感嘆,有的題自己覺得挺簡單,或者聽別人將覺得挺簡單,但是實際操作就容易出現問題,只有自己真的做出來了,理解了,才算是真的會了。
然後說下一題
程式設計題#7:中位數
來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。)
注意: 總時間限制: 2000ms 記憶體限制: 65536kB
描述
中位數定義:一組資料按從小到大的順序依次排列,處在中間位置的一個數或最中間兩個資料的平均值(如果這組數的個數為奇數,則中位數為位於中間位置的那個數;如果這組數的個數為偶數,則中位數是位於中間位置的兩個數的平均值).
給出一組無序整數,求出中位數,如果求最中間兩個數的平均數,向下取整即可(不需要使用浮點數)
輸入
該程式包含多組測試資料,每一組測試資料的第一行為N,代表該組測試資料包含的資料個數,1 <= N <= 15000.
接著N行為N個數據的輸入,N=0時結束輸入
輸出
輸出中位數,每一組測試資料輸出一行
樣例輸入
4 10 30 20 40 3 40 30 50 4 1 2 3 4 0
樣例輸出
25 40 2
提示
這是也一道經典的演算法問題,在企業面試裡出現概率很高,是“找到第K大的數”的變種。先排序再找中位數自然是很直接的做法,但排序本身很慢。我們只想找到第n/2大的數,對於其他數的順序我們並不關心。那麼怎麼在不排序的前提下找到第n/2大的數呢?
這道題到現在我也沒找到不排序的解決辦法,雖然按找第N/2大的數比較容易,但是一旦遇到相同數值的資料,我的方法就會crash,所以最後我還是用的排序進行的解決,如果以後會了,我會進行更新。#include <iostream>
using namespace std;
int main() {
int n, a[15000]; // 一共n個數,n不超過15000。a用來儲存這些數
while (cin >> n) {
if (n == 0)
break;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
//如果n為1或者2的時候就不用排序了,否則排序
if (n == 1) {
cout << a[0] << endl;
}
if (n == 2) {
cout << (a[0] + a[1]) / 2 << endl;
}
// 冒泡,不斷比較相鄰的兩個數,如果順序錯了,那麼就交換
if (n != 1 && n != 2) {
for (int i = 0; i < n - 1; i++) {
for (int j = 1; j < n - i; j++) {
if (a[j - 1] > a[j]) {
int temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
}
}
}
//輸出
if (n % 2 == 0)
cout << (a[n / 2 - 1] + a[n / 2]) / 2 << endl;
if (n % 2 == 1)
cout << (a[n / 2]) << endl;
}
}
return 0;
}
然後是最後一題:
程式設計題#8:校門外的樹
來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。)
注意: 總時間限制: 1000ms 記憶體限制: 65536kB
描述
某校大門外長度為L的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1米。我們可以把馬路看成一個數軸,馬路的一端在數軸0的位置,另一端在L的位置;數軸上的每個整數點,即0,1,2,……,L,都種有一棵樹。
馬路上有一些區域要用來建地鐵,這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止點的座標都是整數,區域之間可能有重合的部分。現在要把這些區域中的樹(包括區域端點處的兩棵樹)移走。你的任務是計算將這些樹都移走後,馬路上還有多少棵樹。
輸入
輸入的第一行有兩個整數L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表馬路的長度,M代表區域的數目,L和M之間用一個空格隔開。接下來的M行每行包含兩個不同的整數,用一個空格隔開,表示一個區域的起始點和終止點的座標。
輸出
輸出包括一行,這一行只包含一個整數,表示馬路上剩餘的樹的數目。
樣例輸入
第一組 500 3 150 300 100 200 470 471 第二組 500 3 100 200 150 160 180 190
樣例輸出
第一組 298 第二組 400
提示
由於資料範圍不大(L<=10000),我們可以使用一個10001長度的陣列來記錄每一個座標上有沒有樹。但想象一下如果資料範圍很大,比如下面這個情況,你怎麼辦呢?
輸入 5000000 3 1500000 3000000 1000000 2000000 4700000 4700001 輸出 2999998最後還是用標記解決的,但是後面的思考題,到現在也沒有解決。
#include<iostream>
using namespace std;
int main() {
int l, m;
cin >> l >> m;
int road[10001];
for (int i = 0; i < l+1; i++) {
road[i] = 1;
}
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
for (int j = a; j < b+1; j++) {
road[j] = 0;
}
}
int count = 0;
for (int i = 0; i < l+1; i++) {
if (road[i] == 1)
count++;
}
cout << count << endl;
return 0;
}