南京大學軟件學院2019夏令營小記

機試兩道題目:1.算法題 2.面向對象編程

時間:3h

第一道題寫的亂七八糟後來發現寫亂了;

第二題沒時間看了,十幾個文件實現一些函數,感覺不難但是需要時間靜下心看,理清之間的關係。

之前羣裏會給你練手用的練習題,給的例題很簡單,考的題目卻很麻煩。

我在這裏只給出第一題的我個人的解題思路。當然,可能不完全對,還望批評指正

1.算法題

這是我的草稿紙:思路大概就是,找到被侵略城市與其他城市的公共結點序列,找到最短的一條,然後斷開最後一個結點與父親的聯繫。

 head.h

#pragma once
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
#define MAXNUM 60000

class tree {
public:
	tree(int n) {
		city = new int[n];
	}
	~tree() {
		delete[] city;
	}
	int *city;//盛放對應下標的父親結點
};

struct innerlink {//就是個放int型的單鏈表
	int k;
	struct innerlink *next;
};

class linktable {
public:
	linktable() :l(NULL){}
	linktable(int n) :value(n), l(NULL) {

	}
	void insert(int b);
	
public:
	
	int value;//對應的城市結點
	struct innerlink *l;//到根節點的路徑
};

func.cpp

#include "head.h"

void linktable::insert(int b) {
	innerlink *t = new innerlink;
	t->k = b;
	t->next = this->l;
	this->l = t;
}

 main.cpp

#include "head.h"

void func(tree &t, int *a);

int n, q;//結點數、襲擊次數
int main() {
	cin >> n >> q;
	tree t(n);
	int *a = new int[n];
	for (int i = 0; i < n; i++) {//給a數組全員賦0
		a[i] = 0;
	}
	t.city[0] = -1;//樹根
	int cur;//臨時變量
	for (int i = 1; i < n; i++) {
		cin >> cur;
		t.city[i] = cur - 1;//接口,因爲內部數組下標從0計數
	}
	char switch_;//+或-
	int recruit;//城市結點
	for (int i = 0; i < q; i++) {
		cin >> switch_;
		cin >> recruit;
		if (switch_ == '+') {
			a[recruit - 1] = 1;//a數組指定位置 遭遇襲擊
			func(t, a);//傳入函數處理
		}
		else if (switch_ == '-') {
			a[recruit - 1] = 0;//a數組指定位置 解除危險
			func(t, a);////傳入函數處理
		}
	}

	cout << "Done" << endl;
	getchar(); getchar();
	return 0;
}

void func(tree &t, int *a) {
	int *b = new int[n];//最終要斷開的結點數組
	int count = 0;//此次遭遇襲擊的城市數目

	for (int i = 0; i < n; i++) {
		b[i] = 0;//初始化 b斷開結點的數組
		if (a[i])
			++count;//襲擊的城市數目加一
	}
	linktable *l = new linktable[count];//“斷開的鏈表”
	int index = 0;
	for (int i = 0; i < n; i++) {//建立 “斷開的鏈表”
		
		if (a[i]) {
			l[index].value = i;
			int j = i;
			while (t.city[j] != -1) {
				l[index].insert(j);
				j = t.city[j];
			}
			++ index;
		}
	}

	//處理每一個 被襲擊的城市結點,按照算法思路來
	for (int i = 0; i < count; i++) {
		int pos = l[i].value;//用於判斷祖先是否斷開
		
		while (t.city[pos] != 0 && b[t.city[pos]] == 0) {//找其祖先是否已經斷開
			pos = t.city[pos];
		}
		if (t.city[pos] != 0) {//如果出現斷開的
			continue;//下一個循環
		}
		else {//斷開指定的一個結點與其父親的連接
			int cur = MAXNUM;
			int cc;//臨時變量
			innerlink *m, *n;
			for (int j = 0; j < count; j++) {	
				cc = 0;//每次都要賦0值,別忘了
				m = l[i].l;
				n = l[j].l;
				while (m && n && m->k == n->k) {
					m = m->next;
					n = n->next;
					++cc;
				}
				if (cc > 0 && cc < cur) {//選擇最小值cur
					cur = cc;
				}
			}

			m = l[i].l;
			--cur;
			while (cur) {
				m = m->next;
				--cur;
			}
			b[m->k] = 1;//鏈表中找到對應位置,斷開b的對應位置(賦1)
		}
	
	}

	//輸出顯示
	int cut_num = 0;
	int total = 0;
	int father;//下面要用到的變量
	for (int i = 0; i < n; i++) {
		if (b[i]) {
			++cut_num;
		}
		father = i;
		bool son = true;
		for (int j = 0; j < n; j++) {
			if (t.city[j] == i) {
				son = false;
				break;
			}
		}
		if (son) {
			while (father != 0) {
				if (b[father]) {
					total++;
					break;
				}
				father = t.city[father];
			}
		}
		
	}

	//顯示結果
	cout << cut_num << " " << total - count << endl;

	cout << "***測試:查看b數組內的情況***" << endl;
	for (int i = 0; i < n; i++) {//////////////
		cout << b[i] << " ";//////////////
	}//////////////
	cout << endl;//////////////
	cout << "*****************************" << endl;
}

 

算法總結:

1.對於下標從0還是1開始,其實完全按照自己的喜好即可,最後在輸入輸出處進行加減1即可。
2.先設計好數據結構(關鍵),考慮到各個步驟的大概可行性,不必分析具體的操作,把握好主要思路。

 

夏令營總結:

1.好好複習別的專業課(所擅長的,一題沒問)
2.刷刷OJ,加深下C++知識
3.英語多練習下日常口語表達和發音
4.搞清楚自己想要什麼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章