前言
今天是2022年蓝桥杯省赛考前的最后一天了,把感觉蓝桥杯比较常用到的模板整理一下吧。先预祝我们都能在明天的比赛中稳定发挥,取得理想的成绩。
一、常考模板
1.全排列模板
全排列在历年考的很多
//排列数字
//DFS 爆搜
#include<bits/stdc++.h>
using namespace std;
const int N = 10;
int n;
int path[N];
bool st[N]; //标志数字是否被用过
void dfs(int u){
if(u == n){ //说明所有位置都已填满
for(int i = 0; i < n;i++){
printf("%d ",path[i]);
}
puts("");
return;
}
for(int i = 1 ; i <= n ;i ++){
if(!st[i]){
path[u] = i;
st[i] = true;//i被使用,改变状态
dfs(u+1);
//回来要恢复原来的状态
st[i] = false;
}
}
}
int main(){
cin >>n;
dfs(0);
return 0;
}
2.dfs
dfs好像也没有什么模板
public static void dfs(int x,int y){
flag[x][y] = true;
System.out.print(a[x][y] + " ");
int dx[] = {0,1,0,-1};
int dy[] = {-1,0,1,0};
for(int i = 0; i < 4;i++){
int nx = x + dx[i];
int ny = y + dy[i];
if(nx < 0 || nx >= n || ny < 0 || ny>=m || flag[nx][ny] == true){
continue;
}
dfs(nx,ny);
}
}
3.bfs
package exer;
import java.util.LinkedList;
import java.util.Queue;
public class 最少次数 {
public static final int N=10000;
public static void main(String[] args) {
int[] st=new int[N];
for(int i=0;i<N;i++) {
st[i]=-1;
}
Queue<Integer> q=new LinkedList<Integer>();
q.offer(2021);
st[2021]=0;
while(!q.isEmpty()) {
int t=q.poll();
if(t==1) {
break;
}
if(st[t+1]==-1) {
st[t+1]=st[t]+1;
q.offer(t+1);
}
if(st[t-1]==-1) {
st[t-1]=st[t]+1;
q.offer(t-1);
}
if(t%2==0&&st[t/2]==-1) {
st[t/2]=st[t]+1;
q.offer(t/2);
}
}
System.out.println(st[1]);
}
}
4.快速幂
//迭代版快速幂
//返回a^k%p
int qmi(int a,int k,int p){
int res = 1;
while(k){
if(k&1){
res = (LL)res*a%p;
}
k>>=1;
a=(LL)a*a%p;
}
return res;
}
5.组合数
组合数好像考的不是很多,但模板很多,这里就写个最简单的暴力模板吧
static long C(int a,int b) {
long res=1L;
for(int i=a,j=1;j<=b;j++,i--) {
res=res*i/j;//一定要写成这样,不要写成res*=i/j,不然会错
}
return res;
}
6.日期问题
calendar类非常好用(java)
package exer;
import java.time.DayOfWeek;
import java.util.Calendar;
//只有每年中的月份是从0开始(1月是0,2月是1),其余的都是从1开始
//周日是每周的第1天,周一是每周第2天,周六是第7天。 calendar.get(Calendar.DAY_OF_WEEK)==2(表示周一)
public class 跑步锻炼 {
public static void main(String[] args) {
Calendar calendar=Calendar.getInstance();
// calendar.set(Calendar.YEAR, 2000);
// calendar.set(Calendar.MONTH,0);
// calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(2000, 0,1);
long sum=0;
while(true) {
if(calendar.get(Calendar.DAY_OF_WEEK)==2||calendar.get(Calendar.DAY_OF_MONTH)==1) {
sum+=2;
}else {
sum+=1;
}
if(calendar.get(Calendar.YEAR)==2020&&calendar.get(Calendar.MONTH)==9) {
break;
}
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
System.out.println(sum);
}
}
手动模拟日历
package exer;
import java.util.Scanner;
public class 回文日期 {
public static int[] months= {0,31,28,31,30,31,30,31,31,30,31,30,31};
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int st=scan.nextInt();
int ed=scan.nextInt();
int ans=0;
for(int i=st;i<=ed;i++) {
int year=i/10000;
int month=i%1000/100;
int day=i%100;
if(check(year,month,day)&&is_HuiWen(i)) {
ans++;
}
}
System.out.println(ans);
}
public static boolean check(int year,int month,int day) {
if(month==0||month>12) {
return false;
}
if(day==0) {
return false;
}
if(month!=2) {
if(day>months[month]) {
return false;
}
}else {
if(year%4==0&&year%100!=0||year%400==0) {
if(day>29) {
return false;
}
}else {
if(day>28) {
return false;
}
}
}
return true;
}
public static boolean is_HuiWen(int n) {
String s=String.valueOf(n);
for(int i=0;i<4;i++) {
if(s.charAt(i)!=s.charAt(7-i)) {
return false;
}
}
return true;
}
}
package exer;
import java.time.DayOfWeek;
import java.util.Calendar;
public class 跑步锻炼 {
public static void main(String[] args) {
//进行日期的模拟,用一个数组去表示每个月的日子,对于闰年的二月去进行特判。
int[] M= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int y=2000,m=1,d=1,w=6,ans=0;
while(y!=2020||m!=10||d!=1) {
if(y%400==0||(y%4==0&&y%100!=0)) {//闰年
M[2]=29;
}else {
M[2]=28;
}
d++;
w=(w+1)%7;//w为0表示星期天
if(d>M[m]) {
d=1;
m++;
}
if(m>12) {
y++;
m=1;
}
if(d==1||w==1) {
ans++;//是月初或者周一会多加1次
}
ans++;
}
//这个循环是先加值再加日期,所以2020.1.10号的已经加上去了,但是2000.1.1没加上,所以加2
ans+=2;
System.out.println(ans);
}
}
7.最短路
dijkstra
#include<bits/stdc++.h>
using namespace std;
const int N = 510,INF=10010;
int g[N][N];
int dist[N];//当前的最短距离
bool st[N];//每个点的最短路是否已经确定
int n,m;
int dijkstra(){
//初始化,起点距离初始化为0,其余点为无穷大
memset(dist,INF,sizeof dist);
dist[1]=0;
for(int i=0;i<n;i++){
//找dist中距离最小的点
int t = -1;
for(int j=1;j<=n;j++){
if( (t==-1||dist[j]<dist[t]) && !st[j]){
t=j;
}
}
//这时起点到t这个点的最短距离已确定,然后更新dist数组
st[t]=true;
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
if(dist[n]>INF/2){
return -1;
}else{
return dist[n];
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j){
g[i][j]=0;
}else{
g[i][j]=INF;
}
}
}
while(m--){
int a,b,w;
cin>>a>>b>>w;
g[a][b]=min(g[a][b],w);
}
cout<<dijkstra()<<endl;
return 0;
}
floyd
#include<bits/stdc++.h>
using namespace std;
const int N=210,INF=1e9;
int n,m,k;
int d[N][N];
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j){
d[i][j]=0;
}else{
d[i][j]=INF;
}
}
}
while(m--){
int a,b,w;
cin>>a>>b>>w;
d[a][b]=min(d[a][b],w);
}
floyd();
while(k--){
int a,b;
cin>>a>>b;
if(d[a][b]>INF/2){
cout<<"impossible"<<endl;
}else{
cout<<d[a][b]<<endl;
}
}
return 0;
}
8.最小生成树
prim
#include<bits/stdc++.h>
using namespace std;
const int N=510,INF=1e5;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int prim(){
int res=0;
//初始化dist数组
for(int i=1;i<=n;i++){
dist[i]=INF;
}
dist[1]=0;
for(int i=0;i<n;i++){
//找最小
int t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1||dist[j]<dist[t])){
t=j;
}
}
//判断最小生成树是否存在
if(dist[t]==INF){
return INF;
} else{
res+=dist[t];
}
//更新
st[t]=true;
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],g[t][j]);
}
}
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j){
g[i][j]=INF;
}else{
g[i][j]=0;
}
}
}
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
g[u][v]=min(g[u][v],w);
g[v][u]=min(g[v][u],w);
}
int t=prim();
if(t==INF){
cout<<"impossible"<<endl;
}else{
cout<<t<<endl;
}
return 0;
}
kruskal
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n,m;
int res;//存最小生成树中所有树边的权重之和
int cnt;//存当前加入了多少条边
int p[N];//并查集,father数组
struct Edge{
int a,b,w;
bool operator< (const Edge &W)const{
return w<W.w;
}
}edges[N];
int find(int x){
if(x!=p[x]){
p[x]=find(p[x]);//路径压缩,不要直接return
}
return p[x];
}
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
edges[i]={a,b,w};
}
//第一步,把所有边从小到大排序
sort(edges,edges+m); //后面是+m,不是+n,容易错
//初始化并查集
for(int i=1;i<=n;i++){
p[i]=i;
}
//从小到大枚举所有边
for(int i=0;i<m;i++){
int a=edges[i].a;
int b=edges[i].b;
int w=edges[i].w;
a=find(a);//a等于a的祖宗结点
b=find(b);//b等于b的祖宗结点
if(a!=b){//如果他们两个的祖宗结点不是同一个
p[a]=b;//合并这两个集合
res+=w;
cnt++;
}
}
if(cnt<n-1){ //这里是<n-1,不是<n,容易错
cout<<"impossible"<<endl;
}else{
cout<<res<<endl;
}
return 0;
}
9.二分
//区间[l,r]被划分成[l,mid]和[mid+1,r]时使用
int bsearch_1(int l,int r){
while(l < r){
int mid = l + r >> 1;
if(check(mid)){//check()判断mid是否满足性质
r = mid;
}else{
l = mid + 1;
}
}
return l;
}
//区间[l,r]被划分成[l,mid-1]和[mid,r]时使用
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;
}
9.最大公约数
//求最大公约数模板(欧几里得算法)
int gcd(int a,int b){
return b!=0 ? gcd(b,a%b) : a;
}
10.最小公倍数
//求最小公倍数代码
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
11.01背包
//朴素写法(二维空间)
//f[i][j]表示只看前i个物品,总体积小于等于j的情况下,总价值最大是多少
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];//左半边的子集
if(j>=v[i]){
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
}
cout<<f[n][m]<<endl;
return 0;
}
12.并查集
int find(int x){
if(p[x] != x){
p[x] = find(p[x]);
}
return p[x];
}
总结
部分模板来源:链接: www.acwing.com.
以上就是整理的一些比较常考到的模板,本人也是第一次参加蓝桥杯,希望我们明天都能取得理想的成绩。