1. 程式人生 > >[土狗之路]coursera上C++基礎第10周作業(下)

[土狗之路]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;
}