南京大学软件学院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.搞清楚自己想要什么

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值