2月28-第五次机试课记录

暴力枚举

  • 多次使用vis记得清空

思路与总结

  • 二分可以优化很多

  • 使用dfs进行暴力搜索要知道两次递归的关系,以及递归一次的时候进行的操作,合理的设置参数来达到某些目的

  • 要能够识别暴力搜索,是有些东西看起来有规律,但是实际上不用讨论规律,直接暴力就能够实现,这种做法往往会被忽略

  • 暴力不代表蛮力,也有优化的地方,有时候要防止枚举重复的

    • 有的时候需要考虑换一种枚举方式暴力反而更简单,更容易进行枚举
    • 暴力也可以通过设置合适的顺序来减少枚举的次数
  • 二进制枚举的几个技巧

    //枚举0-2^n - 1
    int len;
    for(int i = 0; i <(1 << len); i ++){
    	//1<<len 即为 2^n
    }
    
    //取每一位为1进行对于操作
    for(int i = 0; i < len; i ++){
    	if(num & (1 < i)){//num为长度为len的数字,1<i进行移位操作,然后使用&就可以获得对应位的二进制了
    		
    	}
    }
    
    

作业

  • 1108

    • 打表预处理

    • 使用unique优化结果集合

    • 二分法查找顺序集合

      sort(arr, arr + n);
      int size = unique(arr, arr + n) - arr;//unique返回的是排序后多余的下标
      //如 1 2 2 3 4 4 => 1 2 3 2 4 会返回指向第二个2的指针,因此相剪就会变成排序后的长度,再重新利用arr就可以使用去重后的数列
      
  • 1063

    • 埃式打表法求素数,然后判断回文

    • 利用预处理前缀和来快速查找区间的个数

      //打表法求素数
      bool p[N];//false为素数
      void init(){
      	memset(p, 0, sizeof(p));
      	p[1] = [1];//1不是素数
      	for(int i = 2; i < N; i ++){
              if(! p[i]){
      			for(long long j = 1ll * i * i; j < N; j += i){//1.使用longlong,2.递增是+i,不是+1
      				p[j] = true;
      			}
      		}
      	}
      }
      
      //使用前缀和
      int pre[N];
      for(int i = 1; i < N; i ++){
      	if(! p[i] && check(i))
      		sum[i] = sum[i - 1] + 1;
      	else
      		sum[i] = sum[i - 1];
      }
      

题号

  • PIPIOJ 1130: 奇偶交错排列

  • PIPIOJ 1133: 棋盘问题

  • PIPIOJ 1138: N皇后问题

  • PIPIOJ 1102: PIPI学加法

  • PIPIOJ 1049: PIPI的按钮Ⅰ

  • PIPIOJ 1066: 竖式问题

  • PIPIOJ 1322: 同心共筑中国梦

  • PIPIOJ 1084: 最长公共子序列Ⅱ

  • PIPIOJ 1168: PIPI的方格

分析

  • 1130
    • 预处理出所有的和,然后使用二分进行查找
  • 1133
    • 这里对枚举有进行优化,为了防止枚举重复的,可以在参数上设置的更加有技巧,这题我参数设置的是选中一个点后,之后枚举只会枚举后面的点,其实更好的是用行来进行操作
  • 1138
    • 很经典的n皇后问题,只是这里vis数组可以扩展到主副对角线
  • 1102
    • 有个去重的技巧,就是在dfs回溯的时候,去除掉相同的数字,防止重复枚举
  • 1049
    • 其次我一开始想的是两层dfs,这样想不太对,因为针对ans答案输出数组来说,两层dfs都是对这个进行操作,那么应该理解成为一层才对,通过设置参数start,来限制枚举开始的起点,从而让dfs有不同的意义
  • 1084
    • 求最长公共子序列,没有想出来,这里给出答案是使用二进制进行模拟,暴力枚举出所有的子序列,使用hashmap保存后,再之后的字符,每次枚举子序列,看看map查询的到么,如果查到了就保存到临时map,之后使用临时map去更新hashmap,来使得每次求出的子序列得到更新,逐渐缩短
    • 对于多个可能的结果,需要去字典序最小但是又要长度最长,就在最后一次循环中,对hashmap中的子序列进行长度判断,如果长度相同进行字典序判断
    • 环状字符处理的技巧,s+=s;扩展成为双倍
  • 1168
    • 如果直接暴力枚举方阵的状态,不合适,考虑到第一行确定,而剩下的就会确定,因此可以直接使用二进制枚举第一行,然后对第一行进行判断是否合题意(要注意的是最后一行还要判断一次,因为之前的循环只是生成最后一行,最后一行的合法性需要额外拿出来判断)
posted @ 2020-02-28 21:41  fabe2ry  阅读(174)  评论(0编辑  收藏  举报