算法模板

基础算法

二分答案

最大值输出R,最小值输出L
求最大值mid=x时,去掉左半边
求最小值mid=x时,去掉右半边
check函数根据题意写

#include<bits/stdc++.h>
using namespace std;
/*核心代码*/
int A[10010]; //一定要为有序数列才可以使用二分  
int n,m;     //n为数组容量 ,m为所要查找的数;                       
               
/*寻找单个数值的二分*/
int find(int left,int right,int x){ //左右范围,x为所要查找的数 
    while(left<=right){   //当左右边界相等时不结束循环,下一次循环相等查找同一个数。 
		int mid=left+(right-left)/2;
		if(A[mid]==x){
			return mid;          
		}
		else if(A[mid]>x) right=mid-1;
		else left=mid+1;
	}
	return -1;     
}

/*寻找左侧边界的二分查找 */

               //最大值输出r,最小值输出l !!!!! 
               //求最大值mid=x时,去掉左半边
			   //求最小值mid=x时,去掉右半边 

//右边界一直向左靠拢,直到相等,及到达满足条件的最左侧的位置 
int zuo(int left,int right,int x){        
	while(left<=right){ 
	    int mid=left+(right-left)/2;     
		if(A[mid]>=x){
			right=mid-1;
		}       
		else{
			left=mid+1; //最后一次循环结束时,left=right,此时left即为答案,right--小于left结束 
		}
	}
	if(A[left]==x) return left; 
	else return -1;
} 

/*寻找右侧边界的二分查找*/
int you(int left,int right,int x){        
	while(left<=right){ 
	    int mid=left+(right-left)/2;
		if(A[mid]<=x){
			left=mid+1;
		}       
		else{
			right=mid-1;//最后一次循环结束时,left=right,此时right即为答案,left++大于right结束 
		}
	}
	if(A[right]==x) return right; 
	else return -1;
}  

int main(){
	cin>>n>>m; 
	for(int i=1;i<=n;i++) 
	cin>>A[i];
	int a=find(1,n,m);
	cout<<"该数的位置为:"<<a<<endl; 
	int b=zuo(1,n,m);
	cout<<"该数的左边界为:"<<b<<endl;
	int c=you(1,n,m);
    cout<<"该数的右边界为:"<<c<<endl;
return 0;
}
/*
10 3
1 1 2 3 3 3 3 4 5 7
*/

快速排序

#include<iostream> 
#include<algorithm>//用sort排序函数,max,min 
#include<iomanip>// 设置输出位数
#include<cmath>// 使用系统函数,子函数
#include<string> //string a可以用length()判断字符长度
#include<cstdio>  //使用gets()输入字符串 
#include<cstdlib> //使用rand()求随机数 
#include<string.h> //memset重置数组 
int A[1000010];

// 快排 从小到大 
void quickSort(int left,int right){
	int i=left,j=right,base=A[left];   //取最左边的数为基准数
	if(left>=right) return ;           // 循环结束条件 
	
	while(i<j){
		while(A[j]>=base&&i<j)        //从右向左找第一个小于base数的位置  
		j--;
		while(A[i]<=base&&i<j)         //从左向右找第一个大于base数的位置
		i++;
//交换两元素位置		
		if(i<j){                       //如果i还在j左边,交换位置i和j上的数
			swap(A[i],A[j]); 
		}
	}                                 //循环结束时 i=j 
	A[left]=A[i];
	A[i]=base;                       //左端点和结束位置交换值。
	quickSort(left,i-1);//递归左边
	quickSort(i+1,right);//递归右边
} 

using namespace std;

int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>A[i];
	quickSort(1,n);
	for(int i=1;i<=n;i++){
		if(i==n) cout<<A[i];
		else cout<<A[i]<<" "; 
	}
	cout<<endl;
return 0;
} 

小细节合集

上下取整

//向下取整,向上取整 
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
	cout << floor(4)<<endl;
	cout << floor(4.9)<<endl;  //向下 
	cout << ceil(4.111) << endl;
	cout << ceil(4.9) << endl;//向上 
	system("pause");
	return 0;
}

场宽设置

//设置场宽
#include<iostream>
#include<iomanip>
using namespace std;
int a[3][3]={{-1,0,1},{0,1,10,},{1,-10,1}};
int main(){
    for (int i=0;i<3;i++){
        for (int j=0;j<3;j++) {
            cout<<setw(5)<<a[i][j];
            //设置场宽为5 
        }
        cout<<endl;
    }
} 

前后全排列函数

#include <iostream>
#include <algorithm>

using namespace std;

int main(){
	int A[5]={1,2,3,4,5};
	next_permutation(A,A+5); //下一个全排列 
	for(int i=0; i<5; i++){
		cout<<A[i]<<" ";
	}
	cout<<endl;
	prev_permutation(A,A+5); //上一个全排列 
	for(int i=0; i<5; i++){
		cout<<A[i]<<" ";
	}
	cout<<endl;
}

优先队列

top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容

#include<iostream>
#include<queue>
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数

优先队列

// map 容器
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
/*
map容器的定义 
map映射容器的元素数据是由一个键值和一个映射数据组成的,数据类型随便定义 
键值与映照数据之间具有一一映照的关系。且键值唯一。若键值重复,数据会被覆盖 
*/
map<int,char>mp;
int main(){
	//数组方式插入 
	mp[1]='a';
	mp[1]='b';//key不允许重复,再次插入相当于修改value的值 
	mp[2]='a'; 
	mp[3]='b';
	mp[4]='c';
 
    //insert()方式插入
	mp.insert(map<int,char>::value_type(5,'d'));
	
	//通过关键字key删除元素 
	mp.erase('b');
	
	//输出容器大小 
    int s=mp.size();
    
    //遍历输出map中的元素 
	map<int,char>::iterator it=mp.begin();
	while(it!=mp.end())
	{
		cout<<"key:"<<it->first<<" "; 
		cout<<"value:"<<it->second<<endl;;
		it++;
	}
 
    mp.clear();//清空容器
    
    it=mp.find(1);//搜索键值为1的元素 
	/*若该键值存在,则返回该键值所在的
	  迭代器位置,不存在则返回end()迭代器位置 
	*/
	
}
/*

begin() 返回指向 map 头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果 map 为空则返回 true
end() 返回指向 map 末尾的迭代器
erase() 删除一个元素
find() 查找一个元素
insert() 插入元素
key_comp() 返回比较元素 key 的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向 map 尾部的逆向迭代器
rend() 返回一个指向 map 头部的逆向迭代器
size() 返回 map 中元素的个数
swap() 交换两个 map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素 value 的函数
*/ 

搜索

BFS 地图问题

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>

using namespace std;

char map[30][30];     //地图数组 
bool v[30][30];      //访问数组 
int mina=9999,flag=0,m,n,xq,yq,dx[]={1,-1,0,0},dy[]={0,0,1,-1};  //四个方向 

struct point{
	int x,y,step;
};
queue<point> r;     //创建结构体队列 r 

int main(){
	cin>>m>>n;
	memset(v,0,sizeof(v));
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
		cin>>map[i][j];
		if(map[i][j]=='@'){
			xq=i; yq=j;
		}
	}
	}
    point start;                //队列首元素 
	start.x=xq;
	start.y=yq;
	start.step=0;
	r.push(start);
	v[xq][yq]=1;
	
//核心代码 
	while(!r.empty()){            //当队列为空时结束 
		int x=r.front().x,y=r.front().y;            //每次都扩展首元素的位置 
		if(map[x][y]=='*'){       //满足条件输出答案 
			flag=1;
			if(r.front().step<mina) mina=r.front().step;
		}
		for(int i=0;i<4;i++){    //分别向四个方向扩展 
			int tx=x+dx[i];
			int ty=y+dy[i];
			if(!v[tx][ty]&&map[tx][ty]!='#'&&tx>0&&tx<=m&&ty>0&&ty<=n){//x范围为行数,y为列数 ,
//			                                                               如果可以扩展 
				point time;      //创建一个临时结构体        
				time.x=tx;
				time.y=ty;
				time.step=r.front().step+1;
				v[tx][ty]=1;
				r.push(time);     //把结构体放入队列尾部 
			}
		}
		r.pop();                  //队列首元素扩展完毕后移出队列 
	}

	if(flag==0) cout<<"-1"<<endl;
	else cout<<mina<<endl;
return 0; 
}

DFS

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

int w,h,x,y,ans=0;
char map[30][30];
int xx[4]={1,-1,0,0},yy[4]={0,0,1,-1},flag[30][30];  //flag为拜访数组 

//xx和yy分别表示四个方向 
void dfs(int x,int y){
	flag[x][y]=1;          //标识以走过 
	ans++;
	for(int i=0;i<4;i++){   //向四个方向扩展 
		int tx=x+xx[i];
		int ty=y+yy[i];
		if(map[tx][ty]=='.'&& !flag[tx][ty]&&(tx>0&&tx<=w&&ty>0&&ty<=h)){//x范围为行数,y范围为列数 
			dfs(tx,ty);     //递归扩展,直到满足条件或者全部扩展完成结束 
		}
	}
}

int main(){
	cin>>h>>w;
	memset(flag,0,sizeof(flag));
	memset(map,0,sizeof(map));
	for(int i=1;i<=w;i++)
		for(int j=1;j<=h;j++){
			cin>>map[i][j];
			if(map[i][j]=='@'){
				x=i; y=j;     //保存起点 
			} 
		}
	dfs(x,y);
	cout<<ans<<endl;
return 0;
} 

深搜回溯

在数据较小时,爆搜所有可能性,典型问题全排列

#include<iostream>
#include<cmath>
#include<iomanip>

using namespace std;

int n,A[10],v[10],ans[10];

void printf(){  //输出函数 
	for(int i=1;i<=n;i++)
	cout<<setw(5)<<ans[i]; cout<<endl;
    return ;
}
void dfs(int a){
	if(a>n){
		printf();
		return ;
	}
	for(int i=1;i<=n;i++){
		if(v[i]==0){
			v[i]=1;
			ans[a]=A[i];
			a++;    //往下继续走 
			dfs(a);
			a--;   //走不动时原路返回 
			v[i]=0;
			ans[a]=0;
		}
	}
	return ;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) A[i]=i;
	dfs(1);
    return 0;
}

并查集

#include<iostream>
#include<cmath>
using namespace std;
int fa[10010];      //fa表示每个元素的爹 
int find(int x){    //递归找爹函数 ,找最辈分最高的爹 
	if(fa[x]==x) return fa[x];    //自己就是自己的爹,返回自己 
	else{
		fa[x]=find(fa[x]);        // 
		return fa[x];
	}
}
void hb(int x,int y){       //合并函数,两个数输入后以为父子 ,需要认同一个爹 
	int xx=find(x);
	int yy=find(y);
	if(xx==yy) return ;
	else{
		fa[yy]=xx;
	}  
}

int main(){
	int n,m; cin>>n>>m;
	for(int i=1;i<=n;i++) fa[i]=i;
    while(m--){
    	int a,b,c; cin>>a>>b>>c;
    	if(a==1){  //b和c合并到一个集合 
    		hb(b,c);
    		for(int i=1;i<=n;i++) cout<<fa[i]<<" ";
			cout<<endl; 
		}
		else{      //判断是否在一个集合中 
			if(find(b)==find(c)) cout<<"Y"<<endl;
			else cout<<"N"<<endl;
		}
	}
return 0;
} 

最小生成树

kruskal

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,fa[5010],ans=0,sum=0;
//存放每条边的起点终点,权值 
struct side{
	int s,e,l;   
}A[200010];

int find(int x){ //循环找爹函数,不多解释 
	if(x==fa[x]) return x;
	else{
		fa[x]=find(fa[x]);
		return fa[x];
	}
}

void hb(int x,int y){ //第二个人认第一个人做爹函数 
	int xx=find(x);
	int yy=find(y);
	if(xx==yy) return ;
	else{
		fa[yy]=xx;
	}
    return ;
}

bool cmp(side a,side b){ 
	if(a.l<b.l) return 1;
	else return 0;
}

void kruskal(){  
	for(int i=0;i<m;i++){
		int fa1=find(A[i].s),fa2=find(A[i].e);
		if(fa1==fa2) continue;  // 判断两个点是否连通,若连通 则不需要此边 
		ans=max(ans,A[i].l);   
		sum++;   
		//已选择边的个数自加一,当已选择边数为点的个数减一时最小生成树完成 
		hb(fa1,fa2);
		if(sum==n-1) break;
	}
}
int main(){
	cin>>n>>m;
	for(int i=0;i<m;i++){
		cin>>A[i].s>>A[i].e>>A[i].l;
	}
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	sort(A,A+m,cmp);  //按照边的权值排序 
	kruskal();
	cout<<ans<<endl;
return 0;
}

Prim

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const long long maxn=1e4+5;
const long long inf=1e9+5;
long long n,x[maxn],y[maxn],vis[maxn];
//x和y存点的坐标,vis存某个点是否已在最小生成树中 
double d[maxn],ans;
//d存放已生成的树到其他点距离,每次添加最近的点到树中 

double get(long long i,long long j){
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); 
}
void prim(){
	for(long long i=1;i<=n;i++) d[i]=get(1,i);
/*在prim中,我们d数组表示的是第i个点到图中已经有的所有的点的最短距离,
因为用二维存距离的话会直接炸空间,所以我们用的时候在去处理;*/
	d[0]=inf;
	for(long long i=1;i<n;i++){   //只需要n-1条边 
		long long xi=0;
		for(long long j=1;j<=n;j++){
			if(!vis[j]&&(xi==0||d[j]<d[xi])) xi=j;//找到距离最近的那个点
		}
		vis[xi]=1;//往树上加一个点
		ans+=d[xi];
		for(long long j=1;j<=n;j++){
			if(!vis[j]) d[j]=min(d[j],get(xi,j));//更新点距离部分
		}
	}
}

int main(){
	scanf("%lld",&n);
	for(long long i=1;i<=n;i++){
		scanf("%lld%lld",&x[i],&y[i]);
	} 
	vis[1]=1;  //初始点,用此点更新到其他点的距离 
	prim();
	printf("%.2lf",ans);//输出答案
	return 0;
}

DP

背包问题

背包

//w重量,v价值 
// 01
for (int i = 1; i <= n; i++)
    for (int j = m; j >= w[i]; j--)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
        
        
//完全   
 
for (int i = 1; i <= n; i++)
    for (int j = w[i]; j <= m; j++)
        f[j] = max(f[j], f[j - w[i]] + v[i]);  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值