清北学堂培训2019.4.28

Day 1(冯哲)

今天的内容很杂但却都是基础知识

主要分为下面几个点

枚举

枚举也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素。用题目中给定的检验条件判定哪些是无用的,哪些是有用的。能使命题成立的即为其解。
有几个非常非常简单的例题:

这个题目类似于洛谷P1046 陶陶摘苹果

下放代码(不行不行太水了):

#include<iostream>
#include<cstdio>
using namespace std;
int n,x,ans,s[101];
int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        if(x>=s[i])
        {
            ans++;
        }
    }
    cout<<ans;
} 
/*
//洛谷题解qwq
#include<iostream>
using namespace std;
int n,s[10],ans;
int main()
{
    for(int i=0;i<10;i++)
        cin>>s[i];
    cin>>n;
    for(int i=0;i<10;i++)
        if(n>=s[i]-30)
            ans++;
    cout<<ans;
}
*/

 还有就是有关素数判定最laji的方法

#include<iostream>
using namespace std;
int main()
{
    int m;
    cin>>m;
    for(int i=2;i*i<=m;i++)
    {
        if(m%i==0)
        {
            cout<<"合数";
            return 0; 
        }
    }
    cout<<"素数";
}

 没错,就是辣么的简单qwq【当然又双叒叕讲了筛法】

 是个正常人都知道用哪个啊

 还有就是有关枚举的优缺点:

优点:

  • 简单明了,分析直观
  • 能够帮助我们更好地理解问题
  • 运用良好的枚举技巧可以使问题变得更简单

缺点

  • 时空间效率低
  • 往往没有利用题目中的特殊性质
  • 产生了大量冗余状态

 

 搜索

本质上是一种枚举,搜索算法一般做一些普通的枚举不方便表达状态的情况 。

 例题:

给出一个N*N的迷宫,求从起点出发,不经过障碍物到达终点的最短距离

 

解决这类问题一般有两种方式
1.深度优先搜索(DFS【大法师】)
2.广度优先搜索(BFS【笨法师】)

前置知识:

栈:后进先出的数据结构
支持的操作:
加入一个数
删除最晚加入的数
查询最晚加入的数
实现:一个数组+一个用于指向栈顶位置的变量
系统内部递归即使用了栈
例如求斐波那契数列的第n项 :

队列:先进先出的数据结构
支持的操作:
加入一个数
删除最早加入的数
查询最早加入的数
实现:一个数组+头下标+尾下标

DFS的做法图解:

     (a)              (b)          (c)

       (d)         

DFS:

优点:

  • 占用空间小(只需要记录从起点到当前点的路径)
  • 代码短

 缺点:

  • 获得的不一定是最优解
  • 在图上路径非常多的时候,复杂度可能会达到指数级别

 BFS的做法图解:

      (a)          (b)          (c)

 

    (d)           (e)          

 BFS:

优点:

  • 找到答案时找到的一定是最优解
  • 复杂度不会超过图的大小

缺点:

  • 需要维护一个“当前箭头的集合”
  • 空间较大

 BFS与DFS的区别:

  • DFS:能走就走,走不了才回头(比较决绝)
  • BFS:我全都要(要不是笨法师呢qwq)

 应用:

G = (V , E)被称为一张图,则其包含两部分:
1.点集|V | = n,即有n个点,标号分别为1, 2, ..., n
2.边集|E| = m,m条边(ui, vi),表示第ui个点和第vi个点有一条边相连.
边有向边和无向边之分,(u, v)是无向边,u能直接走到v,v能直接走到u.

 还有就是存图的问题:

有这么几种方法:

  1. 邻接矩阵存储,A[x][y] = 0/1表示.优点是便于加删,但是需要O(N^2)的空间.
  2. 直接用vector存下所有的边(邻接表法).优点是空间和访问比较快,缺点是删除比较麻烦.
  3. 之前发的链式前向星

图的连通块

在本课中我们基本只考虑无向图.

a沿着边走可以到b,则称ab在同一个连通块中,称ab连通.

显然ab连通,bc连通,则ac肯定连通.

一张图可以被分成若干个两两连通的块.

这里就只放一个例题吧:

八数码游戏

八数码游戏是一种非常无聊的游戏。给定一个3*3的格子,在其中8个格子中放置整数1 8

剩下一个格子空着(用0表示)。每次操作时,你可以选择将某个与空格相邻的数字移动到空

格上。给定一个初始局面,求最少需要多少次操作才能将局面变成
1 2 3
4 5 6
7 8 0

状态?0 8 的一个排列
转移?一步能够到达的其他排列
BFS or DFS? BFS

按照这个思路,我们就能很好的得出答案:考虑倒着进行游戏过程。所有状态都是由

最终状态转移得到的因此我们以最终态为起点做一遍BFS即可预处理出所有状态的答案

贪心

每一步都取当前的最优解的思想;一般来说符合直观思路;
需要严格的证明;OI中使用多个错误的贪心策略进行加成有时会有良好的效果

例一

给定N个农民,第i个农民有Ai单位的牛奶,单价Pi

现在要求从每个农民手中购买不超过Ai单位,总共M单位的牛奶。

求最小花费
洛谷P1208 [USACO1.3]混合牛奶 Mixing Milk

#include<bits/stdc++.h>

using namespace std;

#define N 5001
#define cmp zhx_ak_ioi//神仙保佑

int n,m,i,sum;

struct node
{
    int x,y;
}a[N];

inline int cmp(node g,node c)
{
    if(g.x!=c.x)
    {
        return g.x<c.x;
    }
    else 
    {
        return g.y>c.y;
    }
}

int main()
{
    cin>>m>>n;
    for(i=1;i<=n;i++)
    {
        cin>>a[i].x>>a[i].y;
    }
    sort(a+1,a+n+1,cmp);
    i=1;
    while(m)
    {
        if(a[i].y)
        {
            a[i].y--;
            sum+=a[i].x;
            m--;
        }
        else
        {
            i++;
        }
    }
    cout<<sum;
} 

二分

给定一个单调的函数/数组;给定一个值,求这个值是否存在;
或者找到这个值应当存在的位置

 

由于数组有序,不妨认为他单调递增
假设Ai > x,则必然有j > i, Aj > x
假设Aj < x,则必然有j < i, Aj < x
二分的原理就是每次在待定区间中选择mid
必然可以确定一边是没有意义的。每次问题的规模缩小 12
因此复杂度为O(logN)

 

顾名思义,就是对答案进行二分
对于某些要求“满足某条件的最小值”类的问题,对答案进
行二分,假设答案不超过mid,则问题变为“满足某条件且
某值不超过mid”的判定性问题。
常用于最大值最小化类问题。
在二分答案之后往往需要一个贪心策略。

相对来说理解起来就简单了

分治

思想:将一个问题划分成若干个(一般都是分成俩)子问题分别解决每个子问题后(也可能是前,还可能一前一后之类的)
将各个子问题组合起来得到原问题的答案。

这里经典的就是快速幂了

归并排序

基本思想:先将整个数组分成两个部分,分别将两个部分排
好序,然后将两个排好序的数组O(n)合并成一个数组。
我们将问题分为两个阶段:分、治

分:

对于每个长度> 1的区间,拆成两个[l, mid]区间和[mid + 1, r]区间
直接递归下去

 

治:

我们认为在处理区间[l,r]时,已经有[l,mid][mid+1,r]内分别有序

这一次的操作就是合并两个有序序列,成为一个新的长有序序列

用两个指针分别指向左右分别走到哪了即可

 

 

 

有关题目的链接:

搜索:
8数码 http://poj.org/problem?id=1077
走迷宫 http://poj.org/problem?id=3984
推箱子 http://acm.hdu.edu.cn/showproblem.php?pid=1254

贪心:
纪念品分组 洛谷P1094
例四:http://codeforces.com/contest/954/problem/E
例五:http://codeforces.com/contest/898/problem/D

二分:
跳石子:NOIP往年题,自行查找题库
例三 http://codeforces.com/contest/954/problem/G
三分 http://codeforces.com/contest/939/problem/E

分治:
平面最近点对:http://acm.hdu.edu.cn/showproblem.php?pid=1007
例二:http://codeforces.com/contest/768/problem/B
例一:http://codeforces.com/contest/97/problem/B

 

posted @ 2019-04-28 21:04  卍GC卐  阅读(300)  评论(0编辑  收藏  举报