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);
}
}