寒假算法学习模板总结

搜索:

bfs:

int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
struct node
{
	int x,y;
}
void bfs()
{
	queue<node>q;//定义一个队列。
	node start,next;
	start.x=dx;
	start.y=dy;//坐标代表起始位置。
	q.push(start);
	while(!q.empty())
	{
		start.x=q.front();//将队列第一个进行处理。
		q.pop();//删除第一个。
		for(int i=0;i<4;i++)//这里是向四个方向进行搜索。
		{
			next.x=start.x+dir[i][0];
			next.y=start.y+dir[i][1];
			if(next.x>=0&&next.x<tt&&next.y>=0&&next.y<tt&&vis[next.x][next.y]==0)
			//这个只是一个判定的条件,要根据题意自己去填写,有点题也用不到标记数组。
			{
				vis[next.x][next.y]=1;//标记已经走过。
				q.push(next);//将新的结构体加入队列。
			}
		}
	}
}

dfs:

void dfs(int x,int y)
{
	for(int i=0;i++;i++)
	{
		int dx=x+dir[i][0];
		int dy=y+dir[i][1];
		//if(里面也是对新的dx,dy进行判断)
		//如果上边使用了标记数组,那么下面要进行解放。如vis[dx][dy]=1;
		dfs(dx,dy);
		//那么递归结束后要进行解放,vis[dx][dy]=0;
		
	}
}

相比较而言,dfs的代码比较简洁,但是bfs也有他自己的好处,比如求最小的步数到终点等等。
两种搜索各有好处,做题时自己进行选择吧。

并查集

//未优化。
void init_set()//初始化
{
    for(int i=1;i<=n;i++){
        s[i]=i;
    }
}
int find_set(int k)//查找
{
    return k==s[k]?k:find_set(s[k]);
}
void union_set(int x,int y)//讲两个有关系的进行关联,将两个集合合成为一个集合。
{
    x=find_set(x);
    y=find_set(y);
    if(x!=y)
        s[x]=s[y];
}
{

优化后:

void init_set()//初始化
{
    for(int i=1;i<=n;i++){
        s[i]=i;
        hight[i]=0;//合并节点。将短的树合并到长的数上。
    }
}
int find_set(int k)//查找优化,路径压缩
{
    if(k!=s[k])
        s[k]=find_set(s[k]);//将每个枝都合并到最后的根节点上,方便后遍的查找
    return s[k];
}
void union_set(int x,int y)//讲两个有关系的进行关联
{
    x=find_set(x);
    y=find_set(y);
    if(hight[x]==hight[y]){
        hight[x]+=1;
        s[y]=x;//将y整棵树合并到x这棵数(集合)上
    }else
    {
        if(hight[x]<hight[y]){
            s[x]=y;
        }
        else
            s[y]=x;
            
    }
}

路径压缩数据较大担心爆栈,可以用非递归。

int find_set(int k)
{
    int t=k;
    while(s[t]!=t)//找根。
        t=s[t];
    int i=k,j;
    while(i!=t)
    {
        j=s[i];
        s[i]=t;
        i=j;
    }
    return t;
}

并查集我现在只是学了一个皮毛,之后会继续学,加强对其的理解与熟悉。

基础dp:

01背包:

//二维数组:
for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        if(w[i]>j)
            dp[i][j]=dp[i-1][j];
        else
            max(dp[i][j]=dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
    }
}
//一维数组
for(int i=1;i<=n;i++){
    for(int j=m;j>=w[i];j--){//可以思考一下为什么要到这循环。
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
}

完全背包:

//二维数组
for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        dp[i][j]=max(dp[i][j-w[i]]+v[i],dp[i-1][j]);
    }
}
//一维数组:
for(int i=1;i<=n;i++){
    for(int j=w[i];j<=m;j++){//正序循环
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
}

dp对我现在来说还是太难了,只能写一些比较基础的模板题,所以只写了最简单的背包问题(还不全面)。随着之后的学习会在写。

dp最重要的就是写状态方程。。。。还是要多练习多思考

字符串:

字典树:

int tire[200][26],cnt[200],idx=1;//二维数组存储字符串,cnt数组为一个标记数组
// idx从1开始,根不做处理。
char s[200];
void add(char str[])//添加单词
{
    int j=0;
    for(int i=0;i<strlen(str);i++){
        int x=str[i]-'a';
        if(tire[j][z]==0)tire[j][z]=idx++;
        j=tire[j][z];
    }
    cnt[j]++;//字符串结束标记一下
}
int Find(char str[])
{
    int j=0;
    for(int i=0;i<strlen(str);i++){
        int z=str[i]-'a';
        if(tire[j][z]==0) return 0;
        j=tire[j][z];
    }
    return cnt[j];
}

kmp:

kmp算法的核心就是求next[]数组。
int Next[1005];//不要定义成next[],在hdu上会出现编译错误。
void get_next(char str[])//得到next数组
{
    int len=strlen(str);
    int i=0,j=-1;
    Next[0]=-1;
    while(i<len){
        if(j==-1||str[i]==str[j]){
            i++;
            j++;
            Next[i]=j;
        }
        else
            j=Next[j];
    }
}
int Find(char str1[],char str2[])//进行查找。
{
    int len1=strlen(str1);
    int len2=strlen(str2);
    int i=0,j=0,ans=0;
    while(i<len1)
    {
        if(j==-1||str1[i]==str2[j])
        {
            i++;
            j++;
        }
        else
            j=Next[j];
        if(j==len2)
        {
            ans++;
            j=0;//根据题目要求来写回溯到的位置,j=next[j];
        }
    }
    return ans;
}

循环的节数=字符串长度–此时next[]数组的数值。
即:len1=len-Next[ len ];
如 abbhkkdabb 循环长度为 7;

最短路:

Floyd:

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
        if(mp[i][k]!=INF)//小优化
        for(int j=1;j<=n;j++){
            if(mp[i][j]>mp[i][k]+mp[k][j]){
                mp[i][j]=mp[i][k]+mp[k][j];
            }
        }
    }
}

还有三种最短路的算法现在还未完全掌握,就先不写了。

初学者比较菜。如果有错误欢迎指出~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值