c++算法模板(一):基础算法模板:

1.高精算法:

加法:

while(i<=a加数的位数|| i<=b加数的位数)

  {    c[i]=a[i]+b[i]+x;

      x=c[i]/10;

      c[i]%=10;

      i++;

}

注意:加法需要逆序储存,因为如果正序储存,那么当加数相加会超过数组的范围。

减法:

   While(lenc<=lena||lenc<=lenb)

{

If(a[i]<b[i])

{

  a[i]+=10;

  a[i+1]--;

}

c[i]=a[i]-b[i];

i++;
}

乘法:

for(i=1;i<=lena;i++)

{

  x=0;

  for(j=1;j<=lenb;j++)

{

c[i+j-1]=a[i]*b[j]+x+c[i+j-1];

x=c[i+j-1]/10;

c[i+j-1]%10;
}

c[i+lenb]=x;

}

Lenc=lena+lenb;

2.排序

<1>桶排序

 #include<iostream>

using namespace std;

int a[10001];

int n,k;

int main()

{

   cin>>n;

   for(int i=1;i<=n;i++)

   {

          cin>>k;

          a[k]++;

   }

   for(int i=1;i<=10000;i++)

   {

          while(a[i]>0)

          {

                   cout<<i<<" ";

                   a[i]--;

      }

   }

   return 0;

}

桶排序算法,复杂度为常数。特别快但是要注意空间。适当的时候用哈希的思想来解决。比如排序:1 4 100000000 7.一共就4个元素但是如果用正常的桶排序的话就要开一个100000001的数组,太费空间。不如就哈希一下。

<2>快排

#include<iostream>

using namespace std;

void qsort(int,int);

int n;

int a[1001];

int main()

{

   cin>>n;

   for(int i=1;i<=n;i++)

         cin>>a[i];

    qsort(1,n);

    for(int i=1;i<=n;i++)

    cout<<a[i]<<" ";

    return 0;

}

void qsort(int l,int r)

{

   int i,j,mid,p;

   i=1;

   j=r;

   mid=a[(l+r)/2];

   do

   {

            while(a[i]<mid) i++;

            while(a[j]>mid) j--;

            if(i<=j)

            {

                     p=a[i];

                     a[i]=a[j];

                     a[j]=p;

                     i++;

                     j--;

            }

   }while(i<=j);

   if(1<j) qsort(l,j); //这里是一不是L

   if(i<r) qsort(i,r);

}

快排的思想在于首先是把数先正好顺序的排列一下。然后一个从头找,一个从找,当前面的大于中间值,后面的小于中间值。这两个交换。当然就有疑问当后面值交换过来比前面的值小怎么办。后面的两个if语句就可以解决这种情况。

<3>归并排序

#include<iostream>

using namespace std;

int a[101],r[101];

void mergesort (int ,int);

int main()

{

   int n,i;

   cin>>n;

   for(i=1;i<=n;i++)

    cin>>a[i];

   mergesort(1,n);

   for(i=1;i<=n;i++)

    cout<<a[i]<<" ";

    return 0;    

}

void mergesort (int s,int t)

{

   int m,i,j,k;

   if(s==t) return ;

   m=(s+t)/2;

   mergesort(s,m);

   mergesort(m+1,t);

   i=s;

   j=m+1;

   k=s;

   while(i<=m && j<=t)

   {

            if(a[i]<=a[j])

            {

                     r[k]=a[i];

                     i++;

                     k++;

            }

            else

            {

                     r[k]=a[j];

                     j++;

                     k++;

            }

   }

   while(i<=m)

   {

            r[k]=a[i];

            i++;

            k++;

   }

   while(j<=t)

   {

            r[k]=a[j];

            j++;

            k++;

   }

   for(i=s;i<=t;i++) a[i]=r[i];

}

归并排序在于利用另一个数组进行排序。利用二分查找的思想来实现。一开始二分二分从第一个开始在一个范围里进行排序,使得在这一个区域里所有的数字以升序排列。返回这个序列给上一次调用,然后与上一层调用在以升序。以此类推到最后则调用结束。

3.递推

<1>斐波那契数列:

F[x]=f[x-1]+f[x-2];

边界条件:f[0]=0,f[1]=1;

前几项数据:0,1,1,2,3,5,8,13,21……

<2>汉罗塔问题:

H[n]=2*H[n-1]+1;

边界:H[1]=1;

前几项数据:1,3,7,15,31,63……

<3>平面分割问题:

A[n]=A[n-1]+2*(n-1);

边界:A[1]=1;

前几项数据:1,3,7,13,21,31……

<4>Catalan数

<5>第二类Stirling数

4.搜索与回溯

 int dfs(int k)

{

         for(int i=1;i<=n;i++)

         {

                   if(符合要求 )

                   {

                            进行标记

                            if(到达目的地)

                            输出

                            else

                            dfs();

                            恢复标记。

                   }

         }

}

int dfs(int k)

{

         if(到达目的地)

                            输出

         for(int i=1;i<=n;i++)

         {

                   if(符合条件 )

                   {

                            保存标记

                            dfs();

                            取消标记

                   }

         }

}

5.贪心与分治

贪心思想:贪心是局部最优解最后推算到全局最优解得过程对最终结果无影响则可以使用。必须给出严格的数学证明。

分治思想:把一个大问题化解成多个小问题,然后在把问题的解合起来组成最后的解。例如归并排序。

6.广度优先搜索

int bfs()

{

         int head,tail;

         head=0;tail=1;

         while(head<tail)

         {

                   head++

                   for(int i=1;i<=目标 ;i++)

                            if(v[i]==0 && map[a[head]][i]==0)

                            {

                                     tail++;

                                     a[tail]=i;

                                     b[tail]=head;

                                     v[i]=1;

                                     if(i==目标 )

                                     {

                                               输出解

                                               head=tail;

                                               break;

                                     }}}}

}

7.动态规划

for(int i=1;i<=目标 ;i++)

         for(int j=1;j<= 目标;j++)

         for(int k=1;k<=目标 ;k++)

          f[j]=max(f[j],f[j-v[i]]+k*w[i]);

          cout<<f[n]<<endl;

0-1背包:注意为倒序

完全背包:为正序

多重背包:为倒序多个添加一个循环

说实话对于动态规划的话,没有什么固定的算法,因为他只是一种思想,没错就是一种思想。所谓的动归,也是一种搜索的系列。只不过它的每一次搜索都会进行储存,但跟记忆化搜索不一样。比如说你有78元钱,我问你这78元钱有多少种组成方案?记忆化搜索一般跟递归搭配。思想不就是,首先从1开始,然后将搜索到的内容存到一个数组里,当再次调用时出来就ok了。而动归的思想在于,我78元钱我不知道怎么分,但是1块钱我知道块分。1块钱的组成方案不就是1张一块的。然后到2块钱,2张1块。以此类推,后一种阶段需要前一种阶段的解读。这样当我知道78元的方案,同时在76的方案数我也计算出来了。这样可以将大规模的数据进行压缩。当然每一次的选择要找最优的(并不是局部最优),例如:当我有abcde五个点,a可以到b,c,c可以到d,b也可以到d。而d可以到e。因为bc两个点都可以到c所以, 比较b,c两条路的长度,选择最优的,因为这样就可以与后面的决策无关。从而选出最优的一条路。这也是dijskra的单源最短路算法的思想。\

栈、队列

关于栈的定义就是说,只能在一段进行插入或删除的特殊线性表。

进栈:

If(top<=n) //栈是否溢出?

{

Top++;

S[top]=x; //入栈

}

退栈:

If(top>=0) //判断栈是否为空?

{

X=s[top];

Top--;   //出栈;

}

队列是指在限定的一段进行插入,另一端进行删除的特殊线性表。

常和BFS进行搭配。

图论

<1>有向图邻接矩阵存储:map[x][y]=z;

无向图邻接矩阵储存:map[x][y]= map[y][x]=z;

Double memset(map,127,sizeof(map));

Int memset(map,0x7f,sizeof(map);

<2>强连通分量:1à2à3à1

在邻接矩阵中: 01102

           00102

           00022

           00002

上面的有向图邻接矩阵共有两个连通分量。后面有关于代码的实现。

<3>邻接表储存

#include<iostream>

#define maxn 1001

using namespace std;

struct Edge

{

         int next;//下一个点;

         int to;//这条边所到达的点;

         int dis;//边的长度;

}edge[maxn];

int head[maxn],num,n,m,u,v,d;

void add_edge(int from,int to,int dis)

{

         num++;

         edge[num].next=head[from];

         edge[num].to=to;

         edge[num].dis=dis;

         head[from]=num;

}

int main()

{

         num=0;

         cin>>n>>m;

         for(int i=1;i<=m;i++)

         {

                   cin>>u>>v>>d;

                   add_edge(u,v,d);

         }

         for(int i=head[i];i!=0;i=edge[i].next)

         {

                   //add 其他代码;

         }

         return 0;

}

本方法的储存方法比较费脑子,有一点逻辑思维。存储时为正序存储,读取时为逆序。

Next

To

Dis

0

2

6

1

3

5

2

4

11

Head[from]=0

Head[from]=1

Head[from]=2

读入的样例:1 2 6

         1     3     5

          1     4     11

<4>图论的遍历

Dfs();从一个点开始,访问一个点,并把此点标记,递归访问下一个,并回朔一步。

关于连通分量的代码:

for(int i=1;i<=n;i++)

               if(v[i]==0)

               {

                        dfs(i);             //bfs(i)枚举一个点进行访问,并标记。

                        sum++;

               }

<4>欧拉道路问题:

定理1:存在欧拉路的条件:图是连通的,并且有2个奇点;

定理2:存在欧拉回路的条件:图是连通的:有0个奇点;

(ps:奇点是连接此点边数有奇数个。)

算法模板:

#include<iostream>

#include<cstring>

#define maxn 1001

using namespace std;

int n,m,start,map[maxn][maxn],x,y,len,c[maxn],ans[maxn];

void dfs (int i)

{

         for(int j=1;j<=n;j++)

         {

                   if(map[i][j]==1)

                   {

                            map[i][j]=map[j][i]=0;

                                dfs(j);

                   }

         }

         len++;

         ans[len]=i;

}

int main()

{

         memset(map,0,sizeof(map));

         cin>>n>>m;

         for(int i=1;i<=m;i++)

         {

                   cin>>x>>y;

                   map[x][y]=map[y][x]=1;

                   c[x]++;

                   c[y]++;

         }

        

         start=1;

         for(int i=1;i<=n;i++)

          if(c[i]%2==1)

            start=i;

         len=0;

         dfs(start);

         for(int i=1;i<=len;i++)

          cout<<ans[i]<<" ";

          return 0;

}

<5>哈密尔顿环

算法模板:

#include<iostream>

#include<cstring>

#define maxn 1001

using namespace std;

int len,x,y,ans[maxn],map[maxn][maxn];

int v[maxn],vis[maxn],num[maxn],n,m,start;

void dfs (int last,int i)

{

         vis[i]=1;

         v[i]=1;

         len++;

         ans[len]=i;

         for(int j=1;j<=num[i];j++)

         {

                   if(map[i][j]==start && map[i][j]!=last)

                   {

                            ans[len+1]=start;

                            for(int i=1;i<=len+1;i++)

                             cout<<ans[i]<<" ";

                            break;

                   }

                   if(vis[map[i][j]]==0) dfs(i,map[i][j]);

         }

         len--;

         vis[i]=0;

}

int main()

{

         cin>>n>>m;

         for(int i=1;i<=m;i++)

         {

                   cin>>x>>y;

                   map[x][++num[x]]=y;

                   map[y][++num[y]]=x;

         }

         for(start=1;start<=n;start++)

         {

                   if(v[start]==0)

                   {

                            len=0;

                            dfs(0,start);

                   }

         }

         return 0;

}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM 算法模板集 Contents 一. 常用函数与STL 二. 重要公式与定理 1. Fibonacci Number 2. Lucas Number 3. Catalan Number 4. Stirling Number(Second Kind) 5. Bell Number 6. Stirling's Approximation 7. Sum of Reciprocal Approximation 8. Young Tableau 9. 整数划分 10. 错排公式 11. 三角形内切圆半径公式 12. 三角形外接圆半径公式 13. 圆內接四边形面积公式 14. 基础数论公式 三. 大数模板,字符读入 四. 数论算法 1. Greatest Common Divisor最大公约数 2. Prime素数判断 3. Sieve Prime素数筛法 4. Module Inverse模逆元 5. Extended Euclid扩展欧几里德算法 6. Modular Linear Equation模线性方程(同余方程) 7. Chinese Remainder Theorem中国余数定理(互素于非互素) 8. Euler Function欧拉函数 9. Farey总数 9. Farey序列构造 10. Miller_Rabbin素数测试,Pollard_rho因式分解 五. 图论算法 1. 最小生成树(Kruscal算法) 2. 最小生成树(Prim算法) 3. 单源最短路径(Bellman-ford算法) 4. 单源最短路径(Dijkstra算法) 5. 全源最短路径(Folyd算法) 6. 拓扑排序 7. 网络预流和最大流 8. 网络最小费用最大流 9. 网络最大流(高度标号预流推进) 10. 最大团 11. 二分图最大匹配(匈牙利算法) 12. 带权二分图最优匹配(KM算法) 13. 强连通分量(Kosaraju算法) 14. 强连通分量(Gabow算法) 15. 无向图割边割点和双连通分量 16. 最小树形图O(N^3) 17. 最小树形图O(VE) 六. 几何算法 1. 几何模板 2. 球面上两点最短距离 3. 三点求圆心坐标 4. 三角形几个重要的点 七. 专题讨论 1. 树状数组 2. 字典树 3. 后缀树 4. 线段树 5. 并查集 6. 二叉堆 7. 逆序数(归并排序) 8. 树状DP 9. 欧拉路 10. 八数码 11. 高斯消元法 12. 字符串匹配(KMP算法) 13. 全排列,全组合 14. 二维线段树 15. 稳定婚姻匹配 16. 后缀数组 17. 左偏树 18. 标准RMQ-ST 19. 度限制最小生成树 20. 最优比率生成树(0/1分数规划) 21. 最小花费置换 22. 区间K大数 23. LCA - RMQ-ST 24. LCA – Tarjan 25. 指数型母函数 26. 指数型母函数(大数据) 27. 单词前缀树(字典树+KMP) 28. FFT(大数乘法) 29. 二分图网络最大流最小割 30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小点基,最小权点基

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值