【冲刺蓝桥杯】背水一战

本文深入探讨了算法在解决实际问题中的应用,包括动态规划在跳跃游戏、路径寻找和分考场问题中的实现,以及并查集在合根植物与城邦问题中的应用。此外,还介绍了二分查找技巧和整数分解的解决方案。通过这些实例,展示了如何利用算法高效地解决复杂问题。
摘要由CSDN通过智能技术生成

1.算式问题(模拟)

题目链接

public class Main {   
    public static int f(int i,int j,int k)
    {
    	 int []v=new int [10];
    	 for(int l=0;l<10;l++)
    		 v[l]=0;
    	 v[0]=1;//这里因为会遇到有0的情况(如307)
    	while(i>0)
    	{
    		if(v[i%10]==1) return 0;
            else v[i%10]=1;

            if(v[j%10]==1) return 0;
            else v[j%10]=1  ;


            if(v[k%10]==1) return 0;
            else v[k%10]=1  ;
    		i/=10;
    		j/=10;
    		k/=10;
    	}
    	return 1;
    }
   int []v=new int [1000];
	public static void main(String[] args) 
	{
	   Scanner cin=new Scanner (System.in);
	   int sum=0;
	   for(int i=123;i<=987;i++)
	   {
		   for(int j=123;j<=987-i;j++)
		   {
			   int k=i+j;
			   if(f(i,j,k)==1)
			 sum++;
		   }
	   }
	   System.out.print(sum);
	}
}

2. 跳跃的小明(动态规划)

跳跃的小明


import java.math.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashSet;
import java.util. Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
public class Main {   
  
	public static void main(String[] args) 
	{
	   Scanner cin=new Scanner (System.in);
	   int n,p,t;
	   n=cin.nextInt();
	   p=cin.nextInt();
	   t=cin.nextInt();
	   int []arr=new int [2500];
	   int [][]dp=new int [2500][2500];//dp[i][j]:一共跳了j次到达了第i格
	   for(int i=1;i<=n;i++)
		   {arr[i]=cin.nextInt();}
       for(int []a:dp)//memset
       {
	   Arrays.fill(a,-0x3f3f3f);
       }
       for(int i=1;i<=n+1&&i<=p;i++)//p的最小值是1,因此是i<=n+1;i<=n+1&&i<=p是因为p可能大于n
    	   dp[i][1]=arr[i];
 /*第i格*/      for(int i=1;i<=n+1;i++)
       {
 /*走的步数*/   	   for(int j=2;j<=t;j++)
    	   {
 /*上一个走了k步到达第i格*/   		   for(int k=1;k<=p&&k<i;k++)
    		   {
    			   dp[i][j]=Math.max(dp[i][j], dp[i-k][j-1]+arr[i]);
    		   }
    	   }
       }
          System.out.print(dp[n+1][t]);
	}
}

3. 路径(动态规划)

路径

import java.math.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashSet;
import java.util. Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
public class Main {   
  
	 public static int gcd(int a,int b)
	    {
	        if(b==0) return a;
	        else return gcd(b,a%b);
	    }
	    public static int lcs(int a,int b)
	    {
	        return a/gcd(a,b)*b;
	    }
	    public static void main(String[] args)  
	    {     
	       Scanner cin=new Scanner(System.in);  
	       int dp[]=new int [200000];
	       
	     for(int i=1;i<=2021;i++)
	    {
	        for(int j=i+1;j<=i+21;j++)
	        {
	            if(j>2021) break;
	            if(dp[j]==0) dp[j]=dp[i]+lcs(i,j);//这一步很细节
	            dp[j]=Math.min(dp[j], dp[i]+lcs(i,j));
	        }
	    }
	    System.out.print(dp[2021]);
	}
}

4. 分考场(dfs)

import java.util.*;
 
public class Main {
    static int n,m,N=110;
    static List<Integer>[] list=new ArrayList[N];
    static int ans=100;
    static boolean[][] map=new boolean[N][N];
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        for (int i = 0; i < m; i++) {
            int a=sc.nextInt();
            int b=sc.nextInt();
            map[a][b]=map[b][a]=true;
        }
        for (int i = 1; i<=n ; i++) {
            list[i]=new ArrayList<>();
        }
        dfs(1,0);
        System.out.println(ans);
    }
    //st是学生,cl是教室数量
    static void dfs(int st,int cl){
        //这步是剪枝操作,很重要,否则可能导致超时
        //当我们判断已用教室已经大于等于找到的最小情况
        //那我们没有必须继续搜索,因为它一定不是答案
        if (cl>=ans) return;
        //到这一步说明找到了一种更小的方案
        if (st>n){
            ans=cl;
            return;
        }
        for (int i = 1;i<=cl ; i++) {
            int j=0;
            for (;j<list[i].size();++j){
                if(map[st][list[i].get(j)]) break;
            }
            //说明和这个教室全部学生都不相等
            if (j==list[i].size()){
                //放入学生
                list[i].add(st);                
                dfs(st+1,cl);
                //回溯
                list[i].remove(list[i].size()-1);
            }
        }
        //走到这步还没找到教室说明需要新教室
        list[cl+1].add(st);
        dfs(st+1,cl+1);
        //回溯
        list[cl+1].remove(list[cl+1].size()-1);
    }
}

4. 二分答案

1.最大化最小值(靠左查找)

	while (l < r)
    {
        int mid = l + r >> 1;	//(l+r)/2
        if (check(mid))  r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }

2.最小值的最大(靠右查找)

	while (l < r)
    {
        int mid = l + r + 1 >> 1;	//(l+r+1)/2
        if (check(mid))  l = mid;
        else r = mid - 1;
    }

3.浮点二分

	while(r-l>1e-5) //需要一个精度保证,看题意
	{
		double mid = (l+r)/2;
		if(check(mid)) l=mid; //或r=mid;
		else r=mid; //或l=mid;
	}

至于check函数中的判断语句怎么写,先判断是哪个模板,之后看对应if(…)右边的是r还是l,如果是r则说明找大的
打包(二分答案)

 
import java.util.Scanner;
 
public class Main {
	static int N=100010;
	static int[] arr=new int[N];
	static int n,m;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		int max=0;
		int sum=0;
		for(int i=1;i<=n;++i) {
			arr[i]=sc.nextInt();
			sum+=arr[i];
			max=Math.max(max, arr[i]);
		}
		int l=max;
		int r=sum;
		while(l<r) {
			int mid=(l+r)>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		System.out.println(l);
	}
	static boolean check(int target) {
		int count=0;
		int tmp=0;
		for(int i=1;i<=n;++i) {
			count+=arr[i];
			if(count>target){
				count=0;
				tmp++;
				i--;
			}else if(i==n){
				tmp++;
			}
		}
		return tmp<=m;
	}
}

5. 合根植物(并查集)

并查集模板

合根植物

import java.util.Scanner;
public class Main {
	static int N=1010;
	static int[][] arr=new int[N][N];
	//并查集
	static int[] p=new int[N*N];
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int m=sc.nextInt();
		
		int count=m*n;
		for(int i=1;i<=n*m;++i) p[i]=i;
		int k=sc.nextInt();
		while(k-->0) {
			int a=sc.nextInt();
			int b=sc.nextInt();
			int root1=find(a);
			int root2=find(b);
			if(root1!=root2){
				p[root1]=root2;
				count--;
			}
		}
		System.out.println(count);
	}
	
	static int find(int x) {
		if(x!=p[x]) p[x]=find(p[x]);
		return p[x];
	}
}

5. 汉诺塔

6. 整数分解(dp)

整数分解

/*https://www.luogu.com.cn/paste/miyd5na7*/
package zkj;
import java.math.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashSet;
import java.util. Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

 
public class Zz {   
        
    public static void main(String[] args) 
	{  
      Scanner cin=new Scanner (System.in);
      long [][]dp=new long[2500][2500];
      for(long []a: dp)
      {
    	  Arrays.sort(a);
      }
      for(int i=1;i<=2021;i++)
      {
    	  dp[1][i]=1;
      }
      for(int i=2;i<=5;i++)
      {
    	  for(int j=1;j<=2021;j++)
    	  {
    		  for(int k=1;k<=2021;k++)
    		  {
    			  if(j-k>0)
    			  dp[i][j]+=dp[i-1][j-k];
    		  }
    	  }
      }
      System.out.print(dp[5][2021]);
      
	}	
}


7. 城邦(并查集+Kruskal)

Kruskal:对边贪心最小生成树

class node 
{
	int a,b,c;
}
class mycompare implements Comparator<node>{
	public int compare(node x,node y)
	{
		return x.c-y.c;
	}
}
public class Zz {   

	static int n=2021;
	static node []e=new node [n*n];
	static int father[]=new int [2023];
	static int find(int x)
	{
		if(x!=father[x]) 
		{
			father[x]=find(father[x]);
		}
		return father[x];
	}
	static int get(int i,int j)
	{
		int res=0;
		int maxn=Math.max(i,j);
		while(maxn>0)
		{
			int aa=i%10;
			int bb=j%10;
			if(aa!=bb)
			{
				res+=aa+bb;
			}
			i/=10;
			j/=10;
			maxn/=10;
		}
		return res;
	}
    public static void main(String[] args) 
	{  
      Scanner cin=new Scanner (System.in);
      for(int i=1;i<=2021;i++)
    	  father[i]=i;
      int m=0;
      for(int i=1;i<=2021;i++)
      {
    	  for(int j=1;j<=2021;j++)
    	  {
    		  e[m]=new node();
    		  e[m].a=i;
    		  e[m].b=j;
    		  e[m].c=get(i,j);
    		  m++;
    	  }
      }
      
      Arrays.sort(e,0,m,new mycompare());
      long res=0;
      for(int i=0;i<m;i++)
      {
    	  int x=e[i].a;
    	  int y=e[i].b;
    	  int z=e[i].c;
    	  if(find(x)!=find(y))
    	  {
    		  res+=e[i].c;
    		  father[find(x)]=find(y);
    	  }
      }
      System.out.print(res);
	}	
}

8.最短路(Floyd+临接矩阵)

void floyd()
{
    for (int k = 1; k <= n; k ++ ) //通过n个点
        for (int i = 1; i <= n; i ++ ) // 遍历所有点对。
            for (int j = 1; j <= n; j ++ )
                arr[i][j] = min(arr[i][j], arr[i][k] + arr[k][j]);
}

9.递增三元组(暴力)

#include<iostream>
#include<algorithm>
using namespace std;
int a[100005],b[100005],c[100005];
typedef long long ll;
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	   cin>>a[i];
	for(int i=0;i<n;i++)
	   cin>>b[i];
	for(int i=0;i<n;i++)
	   cin>>c[i];
	sort(a,a+n);
	sort(b,b+n);
	sort(c,c+n);
	int p1=0,p2=0;
	ll sum=0;
	for(int i=0;i<n;i++)
	{
		while(p1<n&&a[p1]<b[i]) p1++;
		while(p2<n&&c[p2]<=b[i]) p2++;
		sum+=(ll)p1*(n-p2);
	 } 
	cout<<sum<<endl;
	return 0;
}

总结

1.二维数组的初始化任何值,其中下面的dp数组是我们要初始化的对象,

int [][]dp=new int [25][25];
 for(int []a:dp)//memset
       {
	   Arrays.fill(a,-0x3f3f3f);
       }

2.二维vector的使用

ArrayList<Integer>list[]=new ArrayList[100];
for(int i=1;i<=n;i++)
{
   list[i]=new ArrayList();
}

3.二分答案套模板
4.dp模板

import java.math.*;
import java.util.*;
public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
      Scanner cin=new Scanner(System.in);
      int n;
      int []a=new int [50];
      int []dp=new int [50];
      int maxn=-9999;
      n=cin.nextInt();
      for(int i=1;i<=n;i++)
      { a[i]=cin.nextInt();  dp[i]=a[i];}
      /*for(int i=1;i<=n;i++)
      {
    	  dp[i]=1;
    	  for(int j=1;j<i;j++)
    	  {
    		  if(a[i]>a[j])
    		  dp[i]=Math.max(dp[i], dp[j]+1);
    	  }
 	  maxn=Math.max(dp[i], maxn);
      }*/
      for(int i=1;i<=n;i++)
      {
    	  dp[i]=Math.max(dp[i], dp[i-1]+a[i]);
      }
      for(int i=1;i<=n;i++) maxn=Math.max(maxn, dp[i]);
      System.out.print(maxn);
	}

}
/*#include<bits/stdc++.h>
using namespace std;
//求最小全装满的方案数
int a[250];
int dp[250];
const int maxn=0x3f3f3f;
int main()
{

//cin>>n>>sum;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
    cin>>a[i];
dp[0]=0;
for(int i=1;i<=m+1;i++)
    dp[i]=maxn;
for(int i=1;i<=n;i++)
{

    for(int j=a[i];j<=m;j++)
    {

        dp[j]=min(dp[j],dp[j-a[i]]+1);
    }
}
cout<<dp[m];
}
*/
#include<bits/stdc++.h>
using namespace std;
//求最大全装满的方案数
int a[250];
int dp[250];
const int maxn=0x3f3f3f;
int main()
{

//cin>>n>>sum;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
    cin>>a[i];
dp[0]=0;
for(int i=1;i<=m+1;i++)
    dp[i]=-maxn;
for(int i=1;i<=n;i++)
{

    for(int j=m;j>=a[i];j--)
    {

        dp[j]=max(dp[j],dp[j-a[i]]+1);
    }
}
cout<<dp[m];
}

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
using namespace std;
int n,m;//itn dp[m][n]
int dp[500][500];
int main(){

cin>>n>>m;
dp[0][0]=1;
for(int i=1;i<=m;i++)
{
    for(int j=0;j<=n;j++)
{
    if(j-i>=0)
    {
        dp[i][j]=dp[i-1][j]+dp[i][j-i];
    }
    else {
        dp[i][j]=dp[i-1][j];
    }
}
}
cout<<dp[m][n];

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉梦昂志️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值