pat必刷模板第三~四章

p进制转换为十进制,十进制转换为q进制(除基取余法)

//进制转换 p进制转化为十进制(必背) 
int y = 0, product = 1;
while(x != 0){
	y = y + (x % 10) * product;                                //x%10是为了每次获取x的各位数 
	x = x / 10;                                                 //去掉x的个位  
	product = product * p;                                //从个位开始转化 
} 

//十进制y转化为Q进制z
int z[40], num = 0;                  //数组z存放在Q进制y的每一位,num为个数 
do{
	z[num++] = y % Q;                //除基取余 
	y = y / Q;
} while(y != 0);                    //当商不为0时进行循环 

sort函数中cmp的用法

//sort函数的cmp写法
#include<iostream>
using namespace std;
struct stu{   
	int number;
	int score;
};
//用三目运算符写简单的if-else语句 
bool cmp(stu a, stu b){
	return a.score != b.score ? a.score > b.score : a.number < b.number;
	//如果分数不同,按照分数从大到小排序,否则按照学号从小到大排序; 
} 

简单选择排序

//选择排序
//n趟操作,每次选出[i,n]中的最小元素放到前面 
void selectsort(){
	for(int i = 1; i <= n; i++){                //进行n趟操作 
		int k = i;             
		for(int j = i; j <= n; j++){            //选出[i, n]中最小的元素,下标为k 
			if(a[j] < a[k]){
				k = j;
			}
		}
		int temp = a[j];                       //交换a[k]和a[i] 
		a[i] = a[k];
		a[k] = temp;
	}
} 

插入排序

//插入排序
int a[maxn], n;                    //数组下标为1~n 
void insertsort(){
	for(int i = 2; i <= n; i++){            //进行n-1次排序       
		int temp = a[i], j = i;                    //temp临时存放a[i], j从i开始往前枚举 
		while(j > 1 && temp < a[j - 1]){                //只要temp小于前一个元素a[j-1] 
		//从下标j从2到n递增
		//每次都将a[j]插入到1~j中;
		//使的1~j顺序内有序 
			a[j] = a[j - 1];                      //把a[j-1]后移一位至a[j] 
			j--;
		}
		a[j] = temp;                             //插入位置为j 
	}
} 

全排列

//全排列
#include<cstdio>
const int maxn = 11;
int n, p[maxn], hashtable[maxn] = false;
void generatep(int index){   //当前处理第index号位 
	if(index == n + 1){       //边界
	    for(int i = 1; i <= n; i++){
	    	printf("%d", p[i]);    //输出当前排列 
		}        
		printf("\n");//换行      
	    return;
	}
    for(int x = 1; x <= n; x++){     //在递归里枚举1~n,试图将x填入p[index] 
	    if(hashtable[x] == false){       //如果之前没填过,则填入 
		    p[index] = x;
		    hashtable[x] = true;
		    generatep(index + 1);           //填下一个 
		    hashtable[x] = false;             //填完将x还原状态 
		    //从n+1开始退栈,index=n时排出1~n退栈,
			//index=n-1时,因为上层n已经hashtable[n]= false,排出1~n,n-1;倒数第二个排序 
	    }
    }
} 
int main(){
	n = 9;
	generatep(1);  //从index=1填,开始全排列 
	return 0;
}

n皇后(全排列法)

//n皇后
//n个皇后不能同一行,同一列,同一对角线;
//用全排列求解n皇后 
#include<iostream>;
const int maxn = 11;
int n, p[maxn], hashtable[maxn] = {false};
int count = 0;
void generatep(int index){
	if(index == n+1){                         //递归边界,生成一个排列 
		bool flag = true;                       //flag=true表示当前排列为一个合法方案 
		for(int i = 1; i <= n; i++){
			for(int j = i + 1; j <= n; j++){                       //遍历任一两个皇后 
				if(abs(i - j) == abs(p[i] - p[j])){ //如果在同一对角线上 
					flag = false;                   //不合法 
				}
		    }	
		}
		if(flag) count++;                  //若当前方案合法,count+1 
		return;  //返回上层递归 
	}
	for(int x = 1; x <= n; x++){             //全排列递归 
		if(hashtable[x] == false){
			p[index] = x;
			hashtable[x] = true;
			generatep(index + 1);
			hashtable[x] = false;
		}
	}
}

n皇后(回溯法)

//回溯法求n皇后个数 
#include<iostream>
using namespace std;
const int maxn = 11;
int n, p[maxn]; hashtable[maxn] = {false};
int count = 0;
void generatep(int index){
	if(index == n + 1){//递归边界,生成一个合法方案 
		count++; //到这里一定合法 
		return;
	}
	for(int x = 1; x <= n; x++){ //第x行 
		if(hashtable[x] == false){//第x行若没有皇后 
			bool flag = true;//true表示当前皇后不会和之前皇后冲突 
			for(int pre = 1; pre < index; pre++){//遍历之前皇后(回溯检查) 
				if(abs(index - pre) == abs(x - p[pre])){
					flag = false;//若与之前的皇后在一条对角线,冲突 
					break;
				}
			}
			if(flag){//如果可以把皇后放在x行,直接(全排列) 
				p[index] = x; 
				hashatble[x] = true;
				generatep(index + 1);
				hashtable[x] = false;
			}
		}
	}
} 

区间贪心(左右端点)

//区间贪心
//选择尽可能多的不相交开区间 
//总是选择左端点最大的区间
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 110;
struct inteval{
	int x, y;//开区间左右端点 
}I[maxn];
bool cmp(inteval a, inteval b){
	if(a.x != b.x) return a.x > b.x;//先按左端点从大到小排序
	else return a.y < b.y;//左端点相同的按右端点从小到大排序 (总是把最小区间排前面)
} 
int main(){
	int n;
	while(scanf("%d",  &n), n != 0){
		for(int i = 0; i < n; i++){
			scanf("%d%d", &I[i].x, &I[i].y);
		}
		sort(I, I + n, cmp); //把区间排序
	//ans记录不相交区间个数,lastX记录上一个被选中区间的左端点
	    int ans = 1, lastX = I[0].x;//I[0].x是最大的左端点 
        for(int i = 1; i < n; i++){
		    if(I[i].y <= lastX){//若发现一个不相交的区间 
			    lastX = I[i].x;//把该区间的左端点赋为lastX 
			    ans++;//不相交区间+1 
		    }	
	    }
	    printf("%d\n", ans);
	} 
	return 0;
} 

 二分查找

//二分查找
//相关函数


#include
//头文件

//函数模板
binary_search(arr[], arr[]+size, index)
//arr[]数组首地址
//数组元素个数
//index需要查找的值
//函数功能:在数组中以二分法检索的方式查找,若在数组中查找到index元素则true,否则false


lower_bound(arr[], arr[]+size, index)
//函数功能:二分法检索的方式查找,返回>=index的第一个元素位置,如果所有元素都小于index,返回last位置

upper_bound(arr[], arr[]+size, index) 
//函数功能:二分法检索的方式查找,返回>index的第一个元素位置


//解决"寻找有序序列第一个满足某条件的元素的位置"问题的固定模板
//二分区间为左开右闭(left,right]
//初值必须能覆盖解的所有可能取值,并且left比最小值小1(表示左开)
int solve(int left, int right){
	int mid;
	while(left + 1 < right){
		mid = (left + right) / 2;
		条件成立 ? right = mid : left = mid; 
	}
	return right;//返回夹出来的位置 
}

二分法(装水问题)

//二分:装水问题
//半圆半径R,要求装入高度为h的水,使其侧面积:半圆面积 = r,
//给出R和r,求高度h 
#include<cstdio>
#include<cmath>
const double pi = acos(-1.0); //定义pi
const double eps = 1e-5;//精度为10^-5
double f(double R, double h){
	double alpha = 2 * acos((R - h) / R);//h对应的弧的角度 
	double l = 2 * sqrt(R * R - (R - h) * (R - h));//弧对应的直边
	double s1 = alpha * R * R / 2 - l * (R - h) / 2;
	double s2 = pi * R * R / 2;
	return s1 / s2;
} 
double solve(double R, double r){
	double left = 0, right = R, mid;  //[left, right] = [0, R]
	while(right - left > eps){
		mid  = (left + right) / 2;
		f(R, mid) > r ? right = mid : left = mid;
	}
	return mid;//用二分法夹出h 
}
int main(){
	double R, r;
	scanf("%lf%lf", &R, &r);
	printf("%.4f\n", solve)(R, r);
	return 0;
}

快速幂

//快速幂的递归写法
//基于二分思想,又称为二分幂 
//某因子取余相乘再取余保持余数不变 
typedef long long ll;
//求a^b%m
ll binarypow(ll a, ll b, ll m){
	if(b == 0) return 1;//如果b为0,那么a^0 = 1
	//b为奇数,转换为b-1 
	if(b % 2 == 1) return a * binarypow(a, b - 1, m) % m;//对于2^5则为递归2^4再*2 
	else{//b为偶数,转换为b/2 
		ll mul = binarypow(a, b / 2, m);
		return mul * mul % m;//对于2^10,mul为2^5,下个mul为2^2  
	}
} 

//快速幂的迭代写法
typedef long long ll;
ll binarypow(ll a, ll b, ll m){
	ll ans = 1;
	while(b > 0){//如果b的二进制末尾为1(也可以写成if(b%2)) 
		ans = ans * a %m;   //令ans累计上a 
	}
	a = a * a % m;//a平方 
	b >>= 1; //将b的二进制右移1位;即b = b >> 1或b = b / 2; 
} 

two pointers,将两个递增序列合并成一个递增序列

//two pointers
//two pointers充分利用了序列递增的性质,降低复杂度 

//求递增正整数序列,求两个元素之和为一给定定值

//令下标i的初值为0,下标j的初值为n-1 
while(i < j){
	if(a[i] + a[j] == m){
		printf("%d %d\n", i, j);
		i++;
		j--;
	}else if(a[i] + a[j] < m){
		i++;
	}else{
		j--;
	}
} 

//序列合并问题
//假设两个递增序列a和b,要求将它们合并为一个递增序列c
int merge(int a[], int b[]; int c[]; int n; int m){
	int i = 0, j = 0, index = 0;//i指向a[0],j指向b[0]
	while(i < n && j < m){//比较a[]和b[],将其中较小的元素抽到c[]中 
		if(a[i] <= b[j]){
			c[index++] = a[i++];
		}else{
			c[index++] = b[j++];
		}
	} 
	//序列a[]或b[]中未抽完的为大元素
	while(i < n) c[index++] = a[i++]; //将剩余大元素排到c[]中 
	while(i < m) c[index++] = b[j++];
	return index; 
} 

归并排序(也利用了two pointers)

//二路归并排序
//递归实现(用到了two pointers)
const int maxn = 100;
//将数组a[l1,r1]和b[l2,r2]区间合并为有序区间(二路此处l2为r1+1) 
void merge(int a[], int l1, int r1, int l2, int r2){
	int i = l1, j = l2;
	int temp[maxn], index = 0;//temp临时存放合并后的数组 
	while(i <= r1 && j <= r2){
		a[i] <= a[j] ? temp[index++] = a[i++] : temp[index++] = a[j++];
	}
	while(i <= r1) temp[index++] = a[i++];//将剩余大的元素加入序列temp
	while(j <= r2) temp[index++] = a[j++];
	for(i = 0; i < index; i++){
		a[l1 + i] = temp[i];//将合并后的序列赋值回数组a 
	} 
} 
//将array数组当前区间[left, right]进行归并排序
void mergesort(int a[], int left, int right){
	if(left < right){//只要left小于right 
		int mid = (left + right) / 2;//取[left,right]中点 
		mergesort(a, left, mid);
		mergesort(a, mid + 1, right);//左右区间递归(归并排序) 
		merge(a, left, mid, mid + 1, right);//将左区间和右区间合并 
	}
} 
//非递归实现较难 

快速排序

//快速排序(生成随机数)优化后时间复杂度为O(n)

//选取随机主元,对区间[left, right]进行划分
int randpartition(int a[], int left, int right){
	//rand()/RAND_MAX会得到一个[0,1]范围内的浮点数
	//生成[left,right]范围内的随机数p
	int p = (round(1.0*rand()/RAND_MAX*(right-left) + left));
	swap(a[p], a[left]);//交换a[p]和a[left]
	
	//对区间进行[left,right]划分,还是原先的partition函数不动;
	int temp = a[left];//temp为被选中的值(单独存起来) 
	while(left < right){//将比temp大的值全部放在左边,小的值放在右边,中间夹出的就是temp的下标 
		while(left < right && a[right] > temp) right--; //若a[right] > temp()反复左移right 
		a[left] = a[right];//在temp右区间找到比temp小的值,传到left所在的左区间 
		while(left < right && a[left] < temp) left++;
		a[right] = a[left];
	} 
	a[left] = temp;//将temp值传回去; 
	return left;//将相遇的下标返回 (相当于快排一遍)
} 
//快排,left 和right初值分别为(1和n)
void quicksort(int a[], int left, int right){
	if(left < right){
		//将[left,right]按a[left]一分为二
		//左区间都比temp小,右区间都比temp大,且一直递归细分 
		int pos = randpartition(a, left, right);
		quicksort(a, left, pos - 1);
		quicksort(a, pos + 1, right); 
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值