int find(int x) //查找我(x)的掌门
{
int r=x; //委托 r 去找掌门
while (pre[r ]!=r) //如果r的上级不是r自己(也就是说找到的大侠他不是掌门 = =)
r=pre[r ] ; // r 就接着找他的上级,直到找到掌门为止。
return r ; //掌门驾到~~~
int i=x, j; (压缩)
while(i!=r)
{
j=pre[i];
pre[i]=r; // r是不是最后的父亲节点?
r=j;
}
}
void join(int x,int y) //我想让虚竹和周芷若做朋友
{
int fx=find(x),fy=find(y); //虚竹的老大是玄慈,芷若MM的老大是灭绝
if(fx!=fy) //玄慈和灭绝显然不是同一个人
pre[fx ]=fy; //方丈只好委委屈屈地当了师太的手下啦
}
2深度优先搜索(dfs)和 广度优先搜索 (bfs)int Find(int x)
{
if(fa[x]==x)
return x;
return fa[x]=Find(fa[x]);//并查集
}
void Merge(int x,int y)
{
x=Find(x),y=Find(y);
if(x!=y)
fa[y]=x;
}
dfs/
void dfs(int x,int y)
{ if(x<1||x>m||y<1||y>n) return ; // 函数返回值为空 if(s[x][y]!='@')//这个if语句的作用很大 return ; s[x][y]='*'; //标记 for(int i=-1 ; i<=1 ; i++) for(int j=-1 ; j<=1 ; j++) //八个方向 { //也有另外一种写法 即用数组表示 dfs(x+i,y+j); }//这一步递归真的好厉害 }
1.模板一
1 int pow3(int a,int b) 2 { 3 int ans = 1,base = a; 4 while(b!=0) 5 { 6 if(b&1) //?b==1 7 ans *= base; 8 base *= base; 9 b>>=1; //b/2 10 } 11 return ans; 12 }
2.模板二
1 typedef long long ll; 2 ll mod_pow(ll x, ll n, ll mod) 3 { 4 ll res = 1; 5 while(n > 0) 6 { 7 if(n & 1) 8 res = res * x % mod; 9 x = x * x % mod; 10 n >>= 1; 11 } 12 return res; 13 }
3.模板三
1 ll mod_pow(ll x, ll n, ll mod) 2 { 3 if(n == 0) 4 return 1; 5 ll res = mod_pow(x * x % mod, n / 2, mod); 6 if(n & 1) 7 res = res * x % mod; 8 return res; 9 }
4.素数打表
筛选法求素数也重要的求素数方法之一。这种方法主要用于打素数表,如求出n之内的所有素数,其思路是从1开始遇到一个素数就标记一下,并去掉n之内的大于它的所有倍数,直循环到n:
#include<stdio.h>
int n,i,j,a[1000001],p[100000],t=0;
void main()
{
scanf("%d",&n);
a[1]=0;
for(i=2;i<=n;i++)a[i]=1;
for(i=2;i<=n;i++)
if(a[i]){
p[t++]=i;//i即为被记录的素数
for(j=i+i;j<=n;j+=i)a[j]=0;//素数的倍数都标记为零
}
for(i=0;i<t;i++)
printf("%d%c",p[i],i<t-1?' ':'\n');
}
此方法也有局限性,数据量中等时才不会超时,数据量过大时也会超时,而且只能用素数打表,不能对单个数进行判定!(3)这是我根据《离散数学》上的一个定理想到的,
定理为:“若正整数a>1,且a不能被不超过a的平方根的任一素数整除,则a是素数”,实现过程如下:
#include<stdio.h>
#include<math.h>
int p[1000000],a[10000001],t=0;
int prime(int n)
{
int i,q;
q=(int)sqrt(n);
for(i=0;p[i]<=q&&t;i++) //之所以对t取与运算就是为了p[0]
if(n%p[i]==0)return 0;
return 1;
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=2;i<=n;i++)
if(prime(i))p[t++]=i;//这个地方的i,即为上面函数的实参
for(i=0;i<t;i++)//这个if语句能不能实现->运行了一下可以实现
printf("%d%c",p[i],i<t-1?' ':'\n');
}
此方法可以对超大量数据的进行打表!此方法也同样合适于素数打表,判定单个时这个方法不可取!
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;//递归
}
6. 二分查找
#include<iostream> using namespace std; int binary_search(int arr[], int n, int key) { int left = 0; //数组的首位置,即arr[0]处 int right = n - 1;//数组的最后一个位置,即arr[n-1],数组大小为n //循环条件一定要注意 while (left <= right) { int mid = left + ((right - left) >> 1);//此处的mid的计算一定要放在while循环内部,否则mid无法正确更新;并且此处用移位代替除以2可以提高效率,而且可以防止溢出。 if (arr[mid] > key)//数组中间的位置得数大于要查找的数,那么我们就在中间数的左区间找 { right = mid - 1; } else if (arr[mid] < key)//数组中间的位置得数小于要查找的数,那么我们就在中间数的右区间找 { left = mid + 1; } else { return mid;//中间数刚好是要查找的数字。 } } //执行流如果走到此处说明没有找到要查找的数字。 return -1; }
lower_bound()
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置
举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
/*示例 ****哈夫曼编码**** 请输入结点个数:8 输入这8个元素的权值(均为整形): 1:27 2:4 3:87 4:21 5:2 6:21 7:1 8:25 */ #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { unsigned int weight; //用来存储各个结点的权值 unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针 } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树 typedef char *HuffmanCode; //动态分配数组,存储哈夫曼树 ///选择两个parent为0,且weight最小的结点s1和s2 void Select(HuffmanTree *ht,int n,int *s1,int *s2) { int i,min; for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s1=min; for(i=1; i<=n; i++) { if((*ht)[i].parent==0 && i!=(*s1)) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht)[i].parent==0 && i!=(*s1)) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s2=min; } ///构造哈夫曼树ht,w存放已知n个权值 void CrtHuffmanTree(HuffmanTree *ht,int *w,int n) { int m,i,s1,s2; m=2*n-1; //总共的结点数 *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(i=1; i<=n; i++) //1-n号存放叶子结点,初始化 { (*ht)[i].weight=w[i]; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; } for(i=n+1; i<=m; i++) //非叶子结点的初始化 { (*ht)[i].weight=0; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; } printf("\n?哈夫曼树为: \n"); for(i=n+1; i<=m; i++) //创建非叶子结点,建哈夫曼树 { /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2*/ Select(ht,i-1,&s1,&s2); (*ht)[s1].parent=i; (*ht)[s2].parent=i; (*ht)[i].LChild=s1; (*ht)[i].RChild=s2; (*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight; printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight); } printf("\n"); } //从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码 void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n) { char *cd; //定义的存放编码的空间 int a[100]; int i,start,p,w=0; unsigned int c; hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配n个编码的头指针 cd=(char *)malloc(n*sizeof(char)); //分配求当前编码的工作空间 cd[n-1]='\0'; //从右向左逐位存放编码,首先存放编码结束符 for(i=1; i<=n; i++) //求n个叶子结点对应的哈夫曼编码 { a[i]=0; start=n-1; //起始指针位置在最右边 for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent) //从叶子到根结点求编码 { if( (*ht)[p].LChild==c) { cd[--start]='1'; //左分支标1 a[i]++; } else { cd[--start]='0'; //右分支标0 a[i]++; } } hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间 strcpy(hc[i],&cd[start]); //将cd复制编码到hc } free(cd); for(i=1; i<=n; i++) printf(" 权值为%d的哈夫曼编码为:%s\n",(*ht)[i].weight,hc[i]); for(i=1; i<=n; i++) w+=(*ht)[i].weight*a[i]; printf(" 带权路径为:%d\n",w); } int main() { HuffmanTree HT; HuffmanCode HC; int *w,i,n,wei; printf("**哈夫曼编码**\n" ); printf("请输入结点个数:" ); scanf("%d",&n); w=(int *)malloc((n+1)*sizeof(int)); printf("\n输入这%d个元素的权值:\n",n); for(i=1; i<=n; i++) { printf("%d: ",i); fflush(stdin); scanf("%d",&wei); w[i]=wei; } CrtHuffmanTree(&HT,w,n); CrtHuffmanCode(&HT,&HC,n); system("pause"); return 0; }
struct node //结构体
{
int from,to,len;
}edge[maxn];
int n,fa[maxn],m,ans,q;
bool cmp(node a,node b)
{
return a.len<b.len;
}
(此处为模板,上面是可能会用到的一些函数)
int Kruskal()//最小生成树
{
sort(edge,edge+m,cmp);
//对边进行排序,同时整个结构体的元素随着边的排序而排序
for(int i=0;i<n;i++)//初始化
fa[i]=i;
ans=0;
for(int i=0; i<m ;i++)
if(Find(edge[i].from)!=Find(edge[i].to))//连接 避免成环 这步很重要
{
Merge(edge[i].from,edge[i].to);
ans+=edge[i].len;//计数
}
return ans;
}
普利姆算法
- void prim(){
- for(i=1;i<=n;i++){
- dis[i]=map[1][i];
- pre[i]=-1; //map存两点距离,dis存未收入点到收入点距离,pre存该点的父结点
- }
- dis[1]=0;
- pre[1]=0;
- int sum=0,flag,minn;
- for(i=2;i<=n;i++){
- minn=inf;
- for(j=1;j<=n;j++){
- if(pre[j]==-1&&dis[j]<minn){
- flag=j;
- minn=dis[j];
- }
- }
- pre[flag] = i;
- sum+=minn;
- for(j=1;j<=n;j++){
- if(pre[j]==-1&&dis[j]>map[flag][j])
- //更新未收入点到已收入点的最短距离
- dis[j]=map[flag][j];
- }
- }
- printf("%d\n",sum);
- }
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN =1010;
int a[MAXN]; int maxLen[MAXN];
int main()
int N; cin >> N;
for( int i = 1;i <= N;++i)
cin >> a[i]; maxLen[i] = 1; //初始化
}
for( int i = 2; i <= N; ++i)
//每次求以第i个数为终点的最长上升子序列的长度
for( int j = 1; j < i; ++j)
//察看以第j个数为终点的最长上升子序列
if( a[i] > a[j] )
maxLen[i] = max(maxLen[i],maxLen[j]+1); //状态转移方程
cout << * max_element(maxLen+1,maxLen + N + 1 ); //且记录最长的那个上升序列
return 0; //有趣的输出方法
} //时间复杂度O(N2)
“人人为我”递推型动归程序
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30010;
int dp[maxn], a[maxn];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;++i)
scanf("%d",&a[i]);
int ans=0;
for(int i=0;i<n;++i)
{
dp[i]=1;
for(int j=0;j<i;++j)
{
if(a[j]<a[i])
dp[i] = max(dp[i], dp[j]+1);
}
ans=max(dp[i],ans); //×max_element(dp+1,dp+n+1);
printf("%d\n",ans);
}
return 0;
}
//O(nlogn)
#include <cstdio>
#include <algorithm>
#define INF 0x3f3f3f
using namespace std;
int dp[30010],a[30010];
int main()
{
int n,i,j;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;++i)
{
scanf("%d",&a[i]);
dp[i]=INF; //初始化为无穷大
}
for(i=0;i<n;++i)
*lower_bound(dp,dp+n,a[i])=a[i];
printf("%d\n",lower_bound(dp,dp+n,INF)-dp); //如果没有则返回最后一个元素的位置
}
return 0;
}
#include <cstring>
using namespace std;
char sz1[1000];
char sz2[1000];
int maxLen[1000][1000]; //maxLen[i][j]表示第一个串的前i个数字
while( cin >> sz1 >> sz2 ) {
int length1 = strlen( sz1);
int length2 = strlen( sz2);
int i,j;
for( i = 0;i <= length1; i ++ ) //初始化
maxLen[i][0] = 0;
for( j = 0;j <= length2; j ++ )
maxLen[0][j] = 0;
for( i = 1;i <= length1;i ++ ) {
for( j = 1; j <= length2; j ++ ) {
if( sz1[i-1] == sz2[j-1] )
maxLen[i][j] = maxLen[i-1][j-1] + 1;
else
maxLen[i][j] = max(maxLen[i][j-1], //取最大的一个
maxLen[i-1][j]);
}
}
cout << maxLen[length1][length2] << endl;
}
return 0;
}