Pat模板总结

更新到机试当天

格式化输出数字

//格式化输出数字
int len = s.size();
for(int i = 0; i < len; i++) {
    cout << s[i]; //先输出当前位置的数字
    if(s[i] == '-') continue; //负号后面不输出逗号
    if((i + 1) % 3 == len % 3 && i != len - 1) cout << ','; 
}

格式化字符串

//sscanf与sprintf 格式化输入和输出
int sscanf(const char *str, const char *format, ...); 
/*const char*需要使用字符数组,作用:将参数str的字符串根据参数format字符串来转换并格式化数据,转换后将
结果存于对应的参数内*/

int sprintf(char *str, const char *format, ...);
/**作用:格式化字符串**/

 scanf("%s", a); //因a是字符数组的名字,其类型为指针,不需要加&
 sscanf(a, "%lf", &temp); //从字符串a中读取浮点数部分到temp里, temp前需加&
 sprintf(b, "%.2f", temp); //把temp按照小数点后保留不超过两位的格式打印到字符串b里

字符串常用函数

tring s = "Hello World";
string s2 = s;
string s3 = s + s2;
//用cin读入字符串的时候,是以空格为分隔符的,如果想读入一整行的字符串,就需要用getline
string s;
getline(cin, s);
1. =, assign() //赋以新值
2. +=, append(), push_back() //在尾部添加字符
3. insert() //插入字符
4. erase() // 删除字符
5. clear() //清除
6. replace() //替换字符
7. + //串联字符串
8. ==, !=, <, <=, >, >=, compare() //比较字符串
9. find(char) != string::npos //找到char
10.find(char) == string::npos //没找到char 

素数判断

bool isPrime(int n) {
	if(n <= 1) return false;
	int sqr = (int)sqrt(1.0 * n);
	for(int i = 2; i <= sqr; i++) //条件一定是i <= sqr
		if(n % i == 0) return false;
	return true;
}

素数表的获取

const int maxn = 101; //根据需要设定maxn值
int prime[maxn], pNum = 0;
bool p[maxn] = {0}; //p[i] = true表明i是素数
void Find_Prime() {
	for(int i = 1; i < maxn; i++) { //枚举可以从1开始,条件一定是i < maxn;
		if(isPrime(i)) {
			prime[pNum++] = i;
			p[i] = true;
		}
	}
}

筛法获取素数表

const int maxn = 100010;
int prime[maxn], pNum = 0;
bool notprime[maxn] = {false}; //i不是素数,notprime[i] = true;
void Find_Prime() {
	for(int i = 2; i < maxn; ++i) { //一定从2开始,筛法不用调用isPrime函数
		if(!notprime[maxn]) { //如果i是素数
			prime[pNum++] = i; //打表
			for(int j = i + i; j < maxn; j += i) //筛去所有i的倍数,注意增量是j += i;
				notprime[j] = true;
		}
	}
}

堆排序(大顶堆)

/*--向下调整--*/
//heap数组下标为1到n
const int maxn = 1010;
int heap[maxn];
//对heap数组在[low, high]上进行向下调整
//其中low为欲调整结点的数组下标,high一般为堆的最后一个元素的数组下标
void downadjust(int low, int high) {
	int i = low, j = 2 * i; //i为欲调整子树的根结点,j为其左孩子
	while(j <= high) { //存在孩子结点
		if(j + 1 <= high && heap[j + 1] > heap[i]) j = j + 1; 
		if(heap[j] > heap[i]) {
			swap(heap[j], heap[i]); //交换最大权值的孩子与欲调整结点i
			i = j; //保持i为欲调整结点、j为i的左孩子
			j *= 2; //j = 2 * i;
		} else{
			break; //孩子的权值均比欲调整结点i小,调整结束
		}
	}
}

/*--建堆--*/
void createHeap() {
	//从最后一个非叶结点倒着枚举
	for(int i = n / 2; i >= 1; --i) { 
		downadjust(i, n);
	}
}

/*--删除堆顶元素--*/
void deleteTop() {
	heap[1] = heap[n--]; //用最后一个元素覆盖堆顶元素,并让元素总数减一
	downadjust(1, n);
}

/*--向上调整--*/
//对heap数组在[low, high]范围进行向上调整
//low一般为1,high表示欲调整节点的数组下标
void upadjust(int low, int high) {
	int i = high, j = i / 2; //i为欲调整结点,j为其父结点
	while(j >= low) { //j在[low, high]范围内
		//父亲权值小于欲调整结点i的权值
		if(heap[j] < heap[i]) {
			swap(heap[j], heap[i]); 
			i = j;
			j /= 2;
		} else {
			break; //父结点权值比欲调整结点i的权值大,调整结束
		} 
	}
}

/*--添加元素x--*/ 
void insert(int x) {
	heap[++n] = x;
	upadjust(1, n);
}

/*--堆排序--*/
void heapSort() { 
	createHeap(); //建堆
	//节约空间,只在heap数组内部排序
	for(int i = n; i > 1; --i) { //倒着枚举,直到堆中只有一个元素 
		swap(heap[i], heap[1]); //heap[i]与堆顶元素交换
		downadjust(1, i - 1); //调整堆顶
	}
}

DFS剪枝

const int maxn = 30;
int n, V, maxValue = 0;
int w[maxn], c[maxn];
//剪枝
void DFS(int index, int sumW, int sumC) {
	if(index == n) {
		return;
	}
	DFS(index + 1, sumW, sumC);
	//只有加入第index件物品后未超过容量V,才能继续
	if(sumW + w[index] <= V) {
		if(sumC + c[index] > ans) {
			ans = sumC + c[index];
		}
		DFS(index + 1, sumW + w[index], sumC + c[index]);
	}
}

BFS模板

//BFS不是递归函数, 可以有返回值
void BFS(int s) {
	queue<int> q;
	q.push(s);
	inq[s] = true; //树的层序遍历不需要inq数列
	while(!q.empty()) { 
		取出队首元素;
		访问队首元素; //访问可以是任何事情
		将队首元素出队; //一定别忘了出队,否则会死循环
		让队首元素的下一层结点中未曾入队的结点全部入队,并设置为已入队,层号为队首元素层号加一
	}
}

并查集

void init() {
	for(int i = 0; i < n; ++i) {
		father[i] = i;
	}
}
//寻找父结点,并进行路径压缩
int findFather(int x) {
	if(x == father[x]) return x;
	father[x] = findFather(father[x]);
	return father[x];
}
//合并
void Union(int a, int b) {
	int faA = findFather(a);
	int faB = findFather(b); 
	//这里可以更改合并规则,根据题目具体问题具体分析
	if(faA != faB) father[faA] = faB;
}

前序中序转后序

//preL是pre数组中的根结点下标
void post(int preL, int inL, int inR) {
	if(inL > inR) return;
	int i = inL;
	while(i <= inR && in[i] != pre[preL]) ++i;
	int numleft = i - inL; //左子树长度
	post(preL + 1, inL, i - 1);
	post(perL + numleft + 1, i + 1, inR);
	printf("%d ", pre[preL]);
}

中序后序转前序

//postR为post数组中根结点下标
void pre(int postR, int inL, int inR) {
	if(inL > inR) return;
	int i = inL;
	while(i <= inR && in[i] != post[postR]) ++i;
	int numright = inR - i; //右子树长度
	printf("%d ", post[postR]);
	pre(postR - 1 - numright, inL, i - 1);
	pre(postR - 1, i + 1, inR);
}

Dijkstra

//伪码
const int MAXV = 1000;
const int INF = 100000000000;
//G为图,一般设成全局变量,数组d为源点到达各点的最短路径长度,a为起点
int G[MAXV][MAXV], d[MAXV];
Dijkstra (s) {
	初始化;
	for(循环n次) { //注意这里是循环n次,与编号方式无关
		u = 使d[u]最小的还未被访问过的顶点的标号;
		记u已被访问过;
		for(从u出发能到达的所有顶点v) { //邻接表与邻接矩阵版只有以下不同
			if(v未被访问&&以u为中介点生使s到顶点v的最短距离d[v]更优) {
				优化d[v];
			}
		}
	}
}

排名输出

int r = 1;
for(int i = 0; i < n; i++) {
	if(i > 0 && stu[i].score != stu[i-1].score)
		r = i + 1;
	//输出信息,或令stu[i].r = r;
}

AVL

/* 如果调用函数需要改变树形,需要传入node* &root */
struct node {
	int v, height;
	node *lchild, *rchild;
};
node* Newnode(int v) {
	node *root = new node;
	root->v = v;
	root->height = 1;
	root->lchild = root->rchild = nullptr;
}
int getH(node *root) {
	if(root == nullptr) return 0;
	return root->height;
}
int getBF(node *root) {
	return getH(root->lchild) - getH(root->rchild);
}
void updateH(node *root) { //与红黑树获取左右子树高度类似
	root->height = 1 + max(getH(root->lchild), getH(root->rchild));
}

void L(node* &root) { //左旋
	node *temp = root->rchild;
	root->rchild = temp->lchild;
	temp.lchild = root;
	updateH(root);
	updateH(temp);
	root = temp;
}

void R(node* &root) { //右旋
	node *temp = root->lchild;
	root->lchild = temp->rchild;
	temp->rchild = root;
	updateH(root);
	updateH(temp);
	temp = root;
}

void insert(node* &root, int v) {
	if(root == nullptr) {
		root = Newnode(v);
		return;
	}
	if(v < root->v) {
		insert(root->lchild, v);
		updateH(root); //更新的是root
		if(getBF(root) == 2) {
			if(getBF(root->lchild) == 1) {
				R(root);
			} else if(getBF(root->lchild) == -1) {
				L(root->lchild);
				R(root);
			}
		}
	} else {
		insert(root->rchild, v);
		updateH(root);
		if(getBF(root->rchild) == -2) {
			if(getBF(root->rchild) == -1) {
				L(root);
			} else if(getBF(root->rchild) == 1) {
				R(root->rchild);
				L(root);
			}
		}
	}
}

node* create(int data[], int n) {
	node* root = nullptr; //声明root时一定要赋初值为nullptr;
	for(int i = 0; i < n; ++i) {
		insert(root, data[i]);
	}
	return root;
}

高精度整数运算

struct bign
{
	int d[1000];
	int len;
	bign() {
		memset(d, 0, sizeof(d)); //初值全0
		len = 0;
	}
};

bign change(char s[]) { //把字符串转换成高精度整数
	bign a;
	a.len = strlen(s);
	for(int i = 0; i < a.len; ++i)
		a.d[i] = s[a.len - i - 1]; //将数字的高位存放到数组的高位
	return a;
}

bign add(bign a, bign b) {
	bign c;
	int carry = 0;
	for(int i = 0; i < a.len || i < b.len; ++i) {
		int temp = a.d[i] + b.d[i] + carry;
		c.d[c.len++] = temp % 10;
		carry = temp / 10;
	}
	if(carry) {
		c.d[c.len++] = carry;
	}
	return c;
}

int compare(bign a, bign b) {
	if(a.len > b.len) return 1;
	else if(a.len < b.len) return -1;
	else {
		for(int i = a.len - 1; i >= 0; --i) { //从高位开始比较
			if(a.d[i] > b.d[i]) return 1;
			else if(a.d[i] < b.d[i]) return -1;
		}
		return 0;
	}
}

//进行减法之前,将两数进行比较,如果减数比被减数大, 则交换两数
bign sub(bign a, bign b) {
	bign c;
	for(int i = 0; i < a.len || i < b.len; ++i) { //条件是或"||"是因为
												//数组高位都是0
		if(a.d[i] < b.d[i]) { //不够减向高位借位
			a.d[i + 1]--;
			a.d[i] += 10;
		}
		c.d[c.len++] = a.d[i] - b.d[i];
	}
	while(c.len - 1 >= 1 && c.d[c.len] == 0) {
		c.len--; //去除前导零,但是保留至少一位
	}
	return c;
}

//如果有负数,先记录负号,再将绝对值带入函数
bign multi(bign a, int b) {
	bign c;
	int carry = 0;
	for(int i = 0; i < a.len; ++i) {
		int temp = a.d[i] * b + carry;
		c.d[c.len++] = temp % 10;
		carry = temp / 10;
	}
	while(carry) { //carry可能不止一位,所以要用while
		c.d[c.len++] = carry % 10;
		carry /= 10;
	}
	return c;
}

bign divide(bign a, int b, int& r) {
	bign c;
	c.len = a.len;
	for(int i = a.len - 1; i >= 0; --i) { //从高位开始除
		r = r * 10 + a.d[i]; //先更新余数(初始余数为0)
		if(r < b) c.d[i] = 0; 
		else {
			c.d[i] = r / b;
			r = r % b;
		}
	}
	while(c.len - 1 > 0 && c.d[c.len] == 0) {
		c.len--;
	}
	return c;
}

分数运算

int gcd(int a, int b) { //获取最大公约数
	return !b ? a : gcd(b, a % b);
}
struct Fraction {
	int up, down;
};

Fraction reduction(Fraction r) { //化简分数
	if(r.down < 0) { //如果分母是负数,分子分母分别取相反数
		r.up = -r.up;
		r.down = -r.down;
	}
	if(r.up == 0) r.down = 1; //分子是零,分母为 1
	else { 
		int d = gcd(abs(r.up), abs(r.down)); //注意一定是对分子分母的绝对值求最大公约数
		r.up /= d;
		r.down /= d;
	}
	return r;
}

Fraction add(Fraction f1, Fraction f2) {
	Fraction r;
	r.up = f1.up * f2.down + f1.down * f2.up;
	r.down = f1.down * f2.down;
	return reduction(r);
}

Fraction sub(Fraction f1, Fraction f2) {
	Fraction r;
	r.up = f1.up * f2.down - f1.down * f2.up;
	r.down = f1.down * f2.down;
	return reduction(r);
}

Fraction multi(Fraction f1, Fraction f2) {
	Fraction r;
	r.up = f1.up * f2.up;
	r.down = f1.down * f2.down;
	return reduction(r);
}

Fraction divide(Fraction f1, Fraction f2) {
	Fraction r;
	r.up = f1.up * f2.down;
	r.down = f1.down * f2.up;
	return reduction(r);
}

void show(Fractio r) {
	r = reduction(r); //别忘了输出之前先化简
	//if(r.up < 0) printf("(");
	if(r.down == 1) printf("%d", r.up); //整数
	else if(abs(r.up) > abs(r.down)) { //假分数
		printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down); //整数部分带符号,所以是	
																	//r.up / r.down
	} else { //真分数
		printf("%d/%d", r.up, r.down);
	}
	//if(r.up < 0) printf(")");
}

你可能感兴趣的:(Pat模板总结)