算法模板总结

 1.素数筛

//埃氏筛
bool is_prime[MAXN+1];
void init() {
    for(int i = 2; i * i <= MAXN; i++) {
        if(!is_prime[i]) {
            for(int j = i*i; j <= MAXN; j += i) {
                is_prime[j] = 1;
            }
        }
    }
}


//欧拉筛
bool is_prime[MAXN+1];
vector<int> primes; // 存储素数
void init()
{
    for (int i = 2; i <= MAXN; i++)
    {
        if (!is_prime[i])
            primes.push_back(i);
        for (int p : primes)
        {
            if (p * i > n)
                break;
            is_prime[p * i] = 1;
            if (i % p == 0)
                break;
        }
    }
}

2.二分查找

//模板1,可以寻找满足check()时的左边界
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

//模板2,可以寻找满足check()时的右边界
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

 lower_bound()函数

返回值是一个迭代器,指向的是有序数组第一个大于等于key的第一个值的位置

#include<algorithm>
//有序数组用法
int pos = lower_bound(a,a+len,key) - a;
//有序vector用法
int pos = lower_bound(a.begin(),a.end(),key) - a.begin();

3.并查集

#include<iostream>
#include<cstdio>
using namespace std;
int pre[1005];
void init(int n)
{
	for(int i=0;i<=n;i++)
	{
		pre[i]=i;
	}
}
int find(int x)
{
	if(x==pre[x]) return x;
	return pre[x]=find(pre[x]);
}
void join(int a,int b)
{
	int t1=find(a);
	int t2=find(b);
	if(t1!=t2)
	{
		pre[t2]=t1;
	}
}
int main()
{
	int n,m;
	while(~scanf("%d",&n))
	{
		if(n==0) break;
		scanf("%d",&m); 
		init(n);
		for(int i=0;i<m;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			join(a,b);
		}
		int sum=0;
		for(int i=1;i<=n;i++)
		{
			if(pre[i]==i)
			{
				sum++;
			}
		}
		printf("%d\n",sum);//表示有多少个集合或者说分了多少组
	}
	return 0;
}

4.三分

求一个点到抛物线的最小距离

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
double a,b,c,x,y;
double dist(double t)
{
	double yy=a*t*t+b*t+c;
	return 1.0*sqrt((x-t)*(x-t)+(yy-y)*(yy-y));
}
int main()
{
	
	double lm,rm;
	double l=-201.0,r=201.0;
	scanf("%lf%lf%lf%lf%lf",&a,&b,&c,&x,&y);
	while(fabs(l-r)>1e-9)
	{
		lm=1.0*(l+r)/2;
		rm=1.0*(r+lm)/2;
		if(dist(lm)>dist(rm))
		{
			l=lm;
		}
		else
		{
			r=rm;
		}
	}
	printf("%.3lf",1.0*dist(l));
	return 0;
}

5.快速幂与快速乘

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const mod = 1e9+7;
//快速幂
ll quickmi(ll a,ll b)
{
	ll s=1;

	while(b)
	{
		if(b&1) s=s*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return s%mod;
}
//快速乘
ll quickmul(ll a,ll b)
{
    ll res = 0;
    while(b)
    {
        if(b&1) res = (res + a) % mod;
        b>>=1;
        a = a + a % mod;
    }
    return res%mod;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		ll a,b;
		cin>>a>>b;
		printf("%lld\n",quickmi(a,b));
	}
	return 0;
} 

6.矩阵快速幂

A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。

Input

数据的第一行是一个T,表示有T组数据。
每组数据的第一行有n(2 <= n <= 10)和k(2 <= k < 10^9)两个数据。接下来有n行,每行有n个数据,每个数据的范围是[0,9],表示方阵A的内容。

Output

对应每组数据,输出Tr(A^k)%9973。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
struct mat{
    ll a[11][11];
};
int n;
mat operator *(mat x,mat y)   //重载*运算 
{
    mat ans;
    memset(ans.a,0,sizeof(ans.a));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                ans.a[i][j]+=x.a[i][k]*y.a[k][j];
                ans.a[i][j]%=9973;
            }
        }
    }
    return ans;
}
mat quickmi(mat p,int k)
{
	mat b; // 单位矩阵,主对角线为1
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j)
			{
				b.a[i][j]=1;
			}
			else
			b.a[i][j]=0;
		}
	}
	while(k)
	{
		if(k&1)
		b=b*p;
		k>>=1;
		p=p*p;
	}
	return b;
}
int main()
{
	int T;
	int k;
	scanf("%d",&T);
	while(T--)
	{
		ll sum=0;
		struct mat p;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) 
		{
			for(int j=1;j<=n;j++)
			{
				scanf("%lld",&p.a[i][j]); 
			}
		}
		mat t=quickmi(p,k);
		for(int i=1;i<=n;i++)
		{
			
			sum+=t.a[i][i]%9973;
			
		}
		printf("%lld\n",sum%9973);
	}
	return 0;
}

/*
input
2
2 2
1 0
0 1
3 99999999
1 2 3
4 5 6
7 8 9

output
2
2686

*/

7.最短路(Dijkstra单源最短路)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[1005][1005];
int dis[1005];
int vis[1005];
int n,m;
void Dijkstra()
{
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	{
		dis[i]=a[1][i];
	} 
	vis[1]=1;
	for(int k=1;k<n;k++)
	{
		int mint = 999999;
		int u;
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&dis[i]<mint)
			{
				mint=dis[i];
				u=i;
			}
		}
		vis[u]=1;
		for(int i=1;i<=n;i++)
		{
			if(dis[i]>dis[u]+a[u][i])
			{
				dis[i]=dis[u]+a[u][i];
			}
		}
	}
}
int main()
{
	scanf("%d%d",&m,&n);
	memset(a,999999,sizeof(a));
	for(int i=1;i<=n;i++)
	{
		a[i][i]=0;
	}
	for(int j=0;j<m;j++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		a[u][v]=w;
		if(a[v][u]<w)
		{
			a[u][v]=a[v][u];
		}
		else
		{
			a[v][u]=w;
		}
	}
	Dijkstra();
	printf("%d\n",dis[n]);
	return 0;
} 

 最短路前提下最小花费

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct nide
{
	int w,p;
}a[1005][1005];
int vis[1005];
int dis[1005];
int cos[1005];
int n,m;

void Dijkstra(int s)
{
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	{
		dis[i]=a[s][i].w;
		cos[i]=a[s][i].p;
	}
	vis[s]=1;
	for(int k=1;k<n;k++)
	{
		int mint=999999;
		int u;
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&dis[i]<mint)
			{
				mint=dis[i];
				u=i;
			}
		}
		vis[u]=1;
		for(int i=1;i<=n;i++)
		{
			if(dis[i]>dis[u]+a[u][i].w)
			{
				dis[i]=dis[u]+a[u][i].w;
				cos[i]=cos[u]+a[u][i].p;
			}
			else if(dis[i]==(dis[u]+a[u][i].w))
			{
				if(cos[i]>cos[u]+a[u][i].p)
				{
					cos[i]=cos[u]+a[u][i].p;
				}
			}
		}
	}
}
int main()
{
	int s,t;
	while(scanf("%d%d",&n,&m))
	{
		if(!(n||m))
		{
			break;
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				a[i][j].w=a[i][j].p=999999;
				if(i==j)
				{
					a[i][j].w=a[i][j].p=0;
				}
			}
		}
		for(int i=0;i<m;i++)
		{
			int u,v,w,p;
			scanf("%d%d%d%d",&u,&v,&w,&p);
			a[u][v].w=w;
			a[u][v].p=p;
			if(a[v][u].w<w)
			{
				a[u][v].w=a[v][u].w;
				a[u][v].p=a[v][u].p;
			}
			else
			{
				a[v][u].w=w;
				a[v][u].p=p;
			}
		}
		scanf("%d%d",&s,&t);
		Dijkstra(s);
		printf("%d %d\n",dis[t],cos[t]);
	}
	return 0;
} 

8.拓扑排序

HDU - 1285 

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
struct node
{
	int v;//所指向的点 
	int w;//权值 
/*	node(){}
	node(int vv,int ww)
	{
		v=vv;
		w=ww;
	}*/
};

vector<int> G[1005];
int deg[1005];
int a[1005];
int m,n;
void TPsort()
{
	priority_queue<int, vector<int>, greater<int> > q;
	for(int i=1;i<=m;i++)
	{
		if(!deg[i]) q.push(i);
		
	}
	int l=0;
	while(!q.empty())
	{
		int t=q.top();
		q.pop();
		a[++l]=t;
		for(int i=0;i<G[t].size();i++)
		{
			int tt=G[t][i];
			if(deg[tt]>0)
			{
				deg[tt]--;
				if(deg[tt]==0)
				{
					q.push(tt);
				}
			}
		}
	}
}
int main()
{	
	
	while(~scanf("%d%d",&m,&n))//m是边的条数 
	{	
        memset(deg,0,sizeof(deg));
		for(int i=1;i<=m;i++)  G[i].clear();
		for(int i=1;i<=n;i++)
		{
			int u, v;
			scanf("%d%d",&u,&v);
			G[u].push_back(v); 
			deg[v]++;
		}
		TPsort();
		for(int i=1;i<m;i++) printf("%d ",a[i]);
		printf("%d\n",a[m]);
	}
	return 0;
}

9.sudoku

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int mm[11][11];
int row[11][11];
int col[11][11];
int grid[11][11];
bool dfs(int x,int y)
{
	if(x==10)
	return true;
	bool flag=false;
	if(mm[x][y])
	{
		if(y==9)
		{
			flag=dfs(x+1,1);
		}
		else
		{
			flag=dfs(x,y+1);
		}
		if(flag)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		int k=3*((x-1)/3)+(y-1)/3+1;
		for(int i=1;i<=9;i++)
		{
			if(!row[x][i]&&!col[y][i]&&!grid[k][i])
			{
				mm[x][y]=i;
				row[x][i]=1;
				col[y][i]=1;
				grid[k][i]=1;
				if(y==9)
				{
					flag=dfs(x+1,1);
				}
				else
				{
					flag=dfs(x,y+1);
				}
				if(!flag)
				{
					mm[x][y]=0;
					row[x][i]=0;
					col[y][i]=0;
					grid[k][i]=0;
				}
				else
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(row,0,sizeof(row));
		memset(col,0,sizeof(col));
		memset(grid,0,sizeof(grid));
		char mp[11][11];
		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++)
			{
				cin>>mp[i][j];
				mm[i][j]=mp[i][j]-'0';
				if(mm[i][j])
				{
					int k=3*((i-1)/3)+(j-1)/3+1;
					row[i][mm[i][j]]=1;
					col[j][mm[i][j]]=1;
					grid[k][mm[i][j]]=1;
				}
			}
		}
		dfs(1,1);
		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++)
			{
				printf("%d",mm[i][j]);
			}
			printf("\n");
		} 
	}
	return 0;
} 

10.差分数组

差分数组是什么?数组中后一项减前一项生成的数组就是差分数组。

什么问题可以用差分数组?多次修改数组区间的值(如果某个区间都加一个值,或者都减一个值,只需修改差分数组区间的端点值即可,ps:前闭后开)。

//定义diff为原数组nums的差分数组,那么两个数组的关系有:
diff[0] = nums[0]; // 当i=0
diff[i] = nums[i] - nums[i - 1]; // 当i > 0


//可以根据差分数组反过来推算出原有数组
nums[0] = diff[0]; // 当i=0
nums[i] = diff[i] + nums[i - 1]; // 当i > 0


//构建差分数组
void createDiff() {
    diff[0] = nums[0];
    for(int i = 1; i < nums.size(); i++) {
        diff[i] = nums[i] - nums[i-1];
    }
}

//给区间[i,j],增加val(可为负数)
void increment(int i, int j, int val) {
    diff[i] += val;
    if (j + 1 < diff.size()) {
        diff[j + 1] -= val;
    }
}

//还原数组(当然也可以直接在nums数组上操作,节省空间)
void getResult() {
    res[0] = diff[0];
    for(int i = 1; i < nums.size(); i++) {
        res[i] = diff[i] + nums[i-1];
    }
}

11.前缀和与后缀和

724. 寻找数组的中心下标 (可以用前缀和与后缀和方法,也可以先求出总和,然后在遍历数组时求左边的总和,总和-左边的总和就是右边的总和,看左右总和是否相等)

12.双指针法

第一种:快慢指针  283. 移动零

第二种:双端指针,向中间靠  941. 有效的山脉数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值