zoukankan      html  css  js  c++  java
  • 洛谷题单 算法1-3 暴力枚举

    1 First Step (ファーストステップ)

    题目背景
    知らないことばかりなにもかもが(どうしたらいいの?)

    一切的一切 尽是充满了未知数(该如何是好)

    それでも期待で足が軽いよ(ジャンプだ!)

    但我仍因满怀期待而步伐轻盈(起跳吧!)

    温度差なんていつか消しちゃえってね

    冷若冰霜的态度 有朝一日将会消失得无影无踪

    元気だよ元気をだしていくよ

    拿出活力 打起精神向前迈进吧
    在这里插入图片描述

    我们Aqours,要第一次举办演唱会啦!

    虽然学生会长看上去不怎么支持我们的样子,可是有了理事长的支持,我们还是被允许在校内的篮球场里歌唱!

    歌曲也好好地准备过了,名字叫“最喜欢的话就没问题! (ダイスキだったらダイジョウブ!)“,大家一定会喜欢的吧!

    演唱会一定会顺利进行的!

    希望不要发生停电什么的事故哦……!

    题目描述
    可是……这个篮球场,好像很久没有使用过的样子啊……

    里面堆满了学校的各种杂物呢……

    我们Aqours的成员要怎么在里面列队站下呢?

    我们浦之星女子学院的篮球场是一个R行C列的矩阵,其中堆满了各种学校的杂物 (用"#“表示),空地 (用”."表示) 好像并不多的样子呢……

    我们Aqours现在已经一共有K个队员了,要歌唱舞蹈起来的话,我们得排成一条1*K的直线,一个接一个地站在篮球场的空地上呢 (横竖均可)。

    我们想知道一共有多少种可行的站位方式呢。

    Aqours的真正的粉丝的你,能帮我们算算吗?

    输入格式
    第一行三个整数 R, C, K。

    接下来的R行C列,是浦之星女子学院篮球场。

    输出格式
    总共的站位方式数量。

    输入输出样例
    输入
    5 5 2
    .###.
    ##.#.
    …#…
    #…#.
    #.###
    输出
    8
    说明/提示
    R C K 备注
    1-2 <=10 <=10 <=min(R,C) 无
    3-4 <=100 <=100 1 无
    5-6 <=100 <=100 <=min(R,C) 没有障碍
    7-10 <=100 <=100 <=min(R,C) 无
    以下是彩蛋
    在LoveLive!Sunshine!!动画第一季第三集中,Aqours队长高海千歌演唱“最喜欢的话就没问题!”到副歌前时,学校因为雷击停电。

    思路:r和c的范围都不大,我们可以暴力去搜,每次向右搜k-1个点或者向下搜k-1个点,判断是否符合条件即可。需要注意的事,k=1的时候需要特判,这一点容易忽略。因为当k=1的时候,向右和向下搜会造成重复。

    
    
    import java.util.Scanner;
    
    public class Main {
        static char[][] ch;
        static boolean flag;
        static long r,c,k,ans;
        static int[][] next = {{0,1},{1,0}};//右 下
        public static void main(String[] args) {
          Scanner sc = new Scanner(System.in);
          r = sc.nextLong();
          c = sc.nextLong();
          k = sc.nextLong();
          ch = new char[(int)r][];
          for(int i=0;i<r;i++){
              ch[i]=sc.next().toCharArray();
          }
          for(int i=0;i<r;i++){
              for(int j=0;j<c;j++){
                  if(ch[i][j]=='.'&&k!=1){
                      for(int t=0;t<2;t++){
                          int tx = i;
                          int ty = j;
                          flag=false;
                          for(int q=0;q<k-1;q++){
                              tx+=next[t][0];
                              ty+=next[t][1];
                              if(tx>=0&&tx<r&&ty>=0&&ty<c&&ch[tx][ty]=='.'){
                                  continue;
                              }else{
                                  flag=true;
                                  break;
                              }
                          }
                          if(!flag){
                              ans++;
                          }
                      }
                  }else if(ch[i][j]=='.'){
                      ans++;
                  }
              }
          }
          System.out.println(ans);
        }
    }
    

    **

    2 火星人

    **
    题目描述
    人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回答。

    火星人用一种非常简单的方式来表示数字――掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为1,2,3…。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。

    一个火星人用一个人类的手演示了如何用手指计数。如果把五根手指――拇指、食指、中指、无名指和小指分别编号为1,2,3,4和5,当它们按正常顺序排列时,形成了5位数12345,当你交换无名指和小指的位置时,会形成5位数12354,当你把五个手指的顺序完全颠倒时,会形成54321,在所有能够形成的120个5位数中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指时能够形成的6个3位数和它们代表的数字:

    三进制数

    123
    132
    213
    231
    312
    321

    代表的数字

    1
    2
    3
    4
    5
    6

    现在你有幸成为了第一个和火星人交流的地球人。一个火星人会让你看他的手指,科学家会告诉你要加上去的很小的数。你的任务是,把火星人用手指表示的数与科学家告诉你的数相加,并根据相加的结果改变火星人手指的排列顺序。输入数据保证这个结果不会超出火星人手指能表示的范围。

    输入格式
    共三行。
    第一行一个正整数N,表示火星人手指的数目(1≤N≤10000)。
    第二行是一个正整数M,表示要加上去的小整数(1≤M≤100)。
    下一行是1到N这N个整数的一个排列,用空格隔开,表示火星人手指的排列顺序。

    输出格式
    N个整数,表示改变后的火星人手指的排列顺序。每两个相邻的数中间用一个空格分开,不能有多余的空格。

    输入输出样例
    输入
    5
    3
    1 2 3 4 5
    输出
    1 2 4 5 3
    说明/提示
    对于30%的数据,N≤15;

    对于60%的数据,N≤50;

    对于全部的数据,N≤10000;

    思路:这题真是日了狗了 ,菜鸡的我改了足足两个小时。。看了一眼洛谷的题解,45篇题解全是c++,没有一篇java的,好无奈。c++调stl只用十行代码就能ac,但是java不行。我刚开始手写了一个纯暴力的dfs,先找到火星人给的数是多少,然后在加上m,然后继续求全排列。结果内存超限。然后对代码进行了一点优化,此题我们不必在乎外星人给的数是多少,我们只要在火星人给的数的基础上求m次全排列即可。即,我们从外星人给出的全排列开始进行m次dfs,求出来的就是答案。

    import java.util.Scanner;
    
    public class Main {
        static boolean flag;
        static int n,m,count;
        static int[] ok,ans,book;
        public static void main(String[] args) {
            Scanner sc =new Scanner(System.in);
             n = sc.nextInt();
             m = sc.nextInt();
             ok = new int[n];
             ans = new int[n];
             book=new int[n+1];
             for(int i=0;i<n;i++){
                 ok[i]=sc.nextInt();
             }
             dfs(0);
        }
        public static void dfs(int x){
            if(flag){
                return ;
            }
            if(x==n){
                count++;
                if(count>m){
                    for(int i=0;i<n;i++){
                        if(i!=n-1){
                            System.out.print(ans[i]+" ");
                        }else{
                            System.out.print(ans[i]);
                        }
                    }
                    flag =true;
                }
                return ;
            }
            for(int i=1;i<=n;i++){
                if(count==0){
                    i = ok[x];
                }
                if(book[i]==0){
                    ans[x]=i;
                    book[i]=1;
                    dfs(x+1);
                    book[i]=0;
                }
                if(flag){
                    return ;
                }
            }
        }
    }
    

    3 统计方形(数据加强)

    题目背景
    1997年普及组第一题

    题目描述
    有一个n*m方格的棋盘,求其方格包含多少正方形、长方形

    输入格式
    n,m因为原来数据太弱,现规定m小于等于5000,n小于等于5000(原来是100,100)

    输出格式
    方格包含多少正方形、长方形

    输入输出样例
    输入
    2 3
    输出
    8 10

    思路:题意就是让我们在n*m的方格里找有多少个正方形,有多少长方形。这题对于数学菜鸡的我来说,真是不好做啊。。废活不多说,上图,先找规律。
    在这里插入图片描述
    看到这里,规律是不是呼之欲出啊,废话不多说,暴力就完了。

    
    
    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int m = sc.nextInt();
            long ans1 = 0;
            long ans2 = 0;
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    if(i==j){
                        ans1+=(n-i)*(m-j);
                    }else{
                        ans2+=(n-i)*(m-j);
                    }
                }
            }
            System.out.print(ans1+" "+ans2);
        }
    }
    

    4 妖梦拼木棒

    题目背景
    妖梦斩了一地的木棒,现在她想要将木棒拼起来。

    题目描述
    有 n根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法?
    答案对 10^9+7 取模。

    输入格式
    第一行一个整数 n。

    第二行 n 个整数,第 i 个整数 ai 代表第 i 根木棒的长度。

    输出格式
    一行一个整数代表答案。

    输入输出样例
    输入
    4
    1 1 2 2
    输出
    1
    说明/提示
    数据规模与约定
    对于100% 的数据,保证 1≤n≤10 ^5,0≤ai≤5×10 ^3。

    思路:假设四根木棒的长度为a,b,c,d。因为要组成正三角形,所以我们要保证四条木棒的长度符合a + b = c = d。即:四根木棒的长度为a,b,a+b。题目问我们一共有多少种情况,我们可以采用桶排序的方法储存每个长度出现的次数。对于答案,我们可以分两种情况来考虑。
    1: a=b。则ans+=C(a,2)*C(a+b,2)。
    2: a!=b。则ans+=C(a,1)*C(b,1)*C(a+b,2)。
    问题转化为数学问题来求排列组合,需要注意的是,我们要随时取模。同时要注意a与b的大小问题,不然会重复,我们可以规定a>=b。

    import java.util.Scanner;
    public class Main {
        //a + b =a + b
        static long mod = 1000000007,n,max,ans;
        static int[] count = new int[5005];
        public static void main(String[] args){
            Scanner sc = new Scanner(System.in);
            n = sc.nextLong();
            for(int i=0;i<n;i++){
                int t = sc.nextInt();
                count[t]++;
                max = Math.max(max,t);
            }
            for(int a=1;a<=max;a++){
                for(int b=1;b<=a;b++){
                    if(a+b<=max&&count[a+b]>=2){
                        if(a==b&&count[a]>=2){
                            ans=(ans+(count[a]*(count[a]-1)/2)*count[a+b]*(count[a+b]-1)/2)%mod;
                        }else if(a!=b&&count[a]!=0&&count[b]!=0){
                            ans=(ans+count[a]*count[b]*count[a+b]*(count[a+b]-1)/2)%mod;
                        }
                        ans%=mod;
                    }
                }
            }
            System.out.println(ans);
        }
    }
    
    

    5 火柴棒等式

    题目描述
    给你n根火柴棍,你可以拼出多少个形如A+B=C的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0−9的拼法如图所示:
    在这里插入图片描述

    注意:
    加号与等号各自需要两根火柴棍
    如果A≠B则A+B=C与B+A=C视为不同的等式(A,B,C>=0)

    n根火柴棍必须全部用上

    输入格式
    一个整数n(n<=24)。

    输出格式
    一个整数,能拼成的不同等式的数目。

    输入输出样例
    输入
    14
    输出
    2
    输入
    18
    输出
    9

    思路:开一个数组,储存每个数字需要的火柴数。然后直接双重循环枚举a,b,然后a+b得到c,判断是否需要n和火柴即可。

    
    import java.util.Scanner;
    
    
    public class Main {
        static int[] count = {6,2,5,5,4,5,6,3,7,6};
        public static void main(String[] args) {
            Scanner sc =new Scanner(System.in);
            int n = sc.nextInt();
            int ans=0;
            for(int a = 0;a<=2000;a++){
                for(int b = 0;b<=2000;b++){
                    int c = a+b;
                    if(ok(a)+ok(b)+ok(c)+4==n){
                        ans++;
                    }
                }
            }
            System.out.print(ans);
        }
        public static int ok(int x){
            int s = 0;
            if(x==0){
                return 6;
            }
            while(x>0){
                int t = x%10;
                s+=count[t];
                x/=10;
            }
            return s;
        }
    }
    

    6 涂国旗

    题目描述
    某国法律规定,只要一个由 N×M 个小方块组成的旗帜符合如下规则,就是合法的国旗。

    从最上方若干行(至少一行)的格子全部是白色的;
    接下来若干行(至少一行)的格子全部是蓝色的;
    剩下的行(至少一行)全部是红色的;
    现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。

    小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。

    输入格式
    第一行是两个整数 N,M。

    接下来 N 行是一个矩阵,矩阵的每一个小方块是W(白),B(蓝),R(红)中的一个。

    输出格式
    一个整数,表示至少需要涂多少块。

    输入输出样例
    输入
    4 5
    WRWRW
    BWRWB
    WRWRW
    RWBWR
    输出
    11
    思路:枚举白色的终点,蓝色的终点,维护一个最小值即可。

    
    
    import java.util.Scanner;
    
    public class Main {
        static char[][] ch ;
        static int n,m,min;
        static int[] cut1,cut2,cut3;//白 蓝 红
        public static void main(String[] args) {
            Scanner sc =new Scanner(System.in);
            n = sc.nextInt();
            m = sc.nextInt();
            ch =new char[n][];
            for(int i=0;i<n;i++){
                ch[i] = sc.next().toCharArray();
            }
            cut1 = new int[n];
            cut2 = new int[n];
            cut3 = new int[n];
            for(int i=0;i<n;i++){
                for(int j=0;j<ch[i].length;j++){
                    if(ch[i][j]!='W'){
                        cut1[i]++;
                    }
                    if(ch[i][j]!='B'){
                        cut2[i]++;
                    }
                    if(ch[i][j]!='R'){
                        cut3[i]++;
                    }
                }
            }
            int ans=100000000;
            int temp=0;
            for(int i=0;i<=n-3;i++){
                temp=0;
                for(int j=0;j<=i;j++){
                    temp+=cut1[j];
                }
                for(int k=i+1;k<=n-2;k++){
                    int t1 =temp;
                    for(int y=i+1;y<=k;y++){
                        t1+=cut2[y];
                    }
                    for(int q=k+1;q<=n-1;q++){
                        t1+=cut3[q];
                    }
                    ans=Math.min(ans,t1);
                }
            }
            System.out.print(ans);
        }
    }
    

    7 [COCI2008-2009#2] PERKET

    题目描述
    Perket 是一种流行的美食。为了做好 Perket,厨师们必须小心选择配料,以便达到更好的口感。你有N种可支配的配料。对于每一种配料,我们知道它们各自的酸度 S 和甜度 B。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的甜度为每一种配料的甜度的总和。

    众所周知,美食应该口感适中;所以我们希望选取配料,以使得酸度和甜度的绝对差最小。

    另外,我们必须添加至少一种配料,因为没有美食是以白水为主要配料的。

    输入格式
    第一行包括整数 N,表示可支配的配料数。

    接下来 N 行,每一行为用空格隔开的两个整数,表示每一种配料的酸度和甜度。

    输入数据保证,如果我们添加所有配料,总的酸度和甜度都不会超过 10^9。

    输出格式
    输出酸度和甜度的最小的绝对差。

    输入输出样例
    输入
    1
    3 10

    输出
    7

    思路:dfs爆搜,对于每种配料,每次两种情况,选或者不选。维护一个最小值。

    
    
    import java.util.Scanner;
    
    import static java.lang.Math.abs;
    
    public class Main {
        static int n,min=Integer.MAX_VALUE;
        static boolean flag ;
        static int[] arr;
        static long[][] book;
        public static void main(String[] args) {
            Scanner sc =new Scanner(System.in);
            n = sc.nextInt();
            arr = new int[n];
            book = new long[n][2];
            for(int i=0;i<n;i++){
                book[i][0]=sc.nextLong();
                book[i][1]=sc.nextLong();
            }
            dfs(0,0);
            System.out.print(min);
        }
        public static void dfs(int x,int y){
            if(x==n){
                long a=1;
                long b=0;
                flag =false;
                for(int i=0;i<n;i++){
                    if(arr[i]==1){
                        flag=true;
                        a*=book[i][0];
                        b+=book[i][1];
                    }
                }
                if(flag){
                    long t =a-b;
                    min = (int) Math.min(abs(t),min);
                }
                return ;
            }
            dfs(x+1,y);
            arr[x]=1;
            dfs(x+1,y+1);
            arr[x]=0;
        }
    }
    
  • 相关阅读:
    vue_源码 原理 剖析
    vue_vuex
    vue_VueRouter 路由_路由器管理n个路由_并向路由组件传递数据_新标签路由_编程式路由导航
    vue_mint-ui
    vue_ajax 请求
    vue_组件间通信:自定义事件、消息发布与订阅、槽
    vue_小项目_吃饭睡觉打豆豆
    vue-cli 脚手架 Command Line Interface
    程序员面试金典-面试题 04.03. 特定深度节点链表
    程序员面试金典-面试题 04.02. 最小高度树
  • 原文地址:https://www.cnblogs.com/fxzemmm/p/14847933.html
Copyright © 2011-2022 走看看