ACM周总结2

目录:

一,搜索

一问:什么是搜索,搜索的本质是什么?

 深搜:(DFS)

应用场景:

基础的点:

两道例题:

注意点:

注意:

搜索(剪枝):

基本概念:

简单介绍:

例题:(最优性剪枝)

例题2:(可行性剪枝) 

广搜:(BFS)

应用场景:

模板:

注意:

例题1:

 例题2:

二,蓝桥杯的总结:

例1:(欧拉定理)

注意点:

例2:(动态规划入门)

数字三角形(基础篇):

2.进阶版本: 

三,关于Codefores比赛的总结

 比赛总结:

关于STL如何降低复杂度?

贪心思想:

四,周总结


一,搜索

一问:什么是搜索,搜索的本质是什么?

暴力将每一种答案都搜索一遍,找出符合条件的输出(在我看来就这样)

 深搜:(DFS)

1.不管有多少路,都先一条路走到黑,不行再返回上一条路,再选择另一条路。

2.dfs的重点在于回溯(用VIS数组进行标记)

3.大部分情况下用递归的方式进行实现。

应用场景:

1.只要我能够找到这个答案就行(暴力的一种思想),我不管,我就有这个东西就行,不管在哪。

2.迷宫问题中:我是否有路径能够走出迷宫。

基础的点:

算法笔记DFS总结1_钟一淼的博客-CSDN博客

两道例题:

解释一下我的思想:(我题目的分析应该都比较明确)  

P1036洛谷选数_钟一淼的博客-CSDN博客

注意点:

1.回溯上,因为这边累加的和进行回溯操作。

2.单独设置一个变量进行记录访问到第几个数了。

最经典的就是八皇后问题,在这里我就不细说了。

注意:

        dfs并不适合搜寻最短路径问题,因为每一种情况它都需要遍历一遍,而运用BFS就可以直接return掉很多条路径,时间复杂度就会降低很多。(从而不会被超时)。

搜索(剪枝):

基本概念:

树的分支给砍掉。

简单介绍:

1.优化搜索顺序,先去搜索那些分支短的结点。

2.等效的消除:如果分支相等的话就没必要再次进行搜索了。

3.可行性剪枝:发现分支无法满足递归条件,掉进了死胡同了,就可以直接剪掉了。

4.最优性剪枝求最短路径,求最小值,寻找最优解的时候应用,如果当前状态就已经不满足最优条件了,那之后无论什么状况都不能满足了,就直接剪掉。

例题:(最优性剪枝)

P1433 吃奶酪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <iostream>
#include <cmath>
using namespace std;
int n;
bool vis[20];	
double a[20], b[20];	
double ans = 2222222222.0;	
double suanshi(int x, int y)
{
	return sqrt((a[x] - a[y]) * (a[x] - a[y]) + (b[x] - b[y]) * (b[x] - b[y]));
}
 
void dfs(int p, double len, int m)//p
{
	if (len > ans)	return;//最优性剪枝,我现在的分支就已经不满足条件了,我继续往下搜索没有任何意义
	if (m == n) {//递归到点数与题目相同时
		ans = len;//让ans取得最小值
		return;
	}
	for (int i = 1; i <= n; i++)
	{
		if (vis[i]==false) {	
			vis[i] = true;
			dfs(i, len + suanshi(p, i), m + 1);
			vis[i] = false;
		}
	}
}
 
int main()
{
	ios::sync_with_stdio(false);//加快速度
	cin>>n;
	a[0] = 0;b[0] = 0;
	for (int i = 1; i <= n; i++)
		cin >> a[i] >> b[i];
	dfs(0, 0.0, 0);
	printf("%.2lf", ans);
	return 0;
}

例题2:(可行性剪枝) 

POJ 1419-Graph Coloring_钟一淼的博客-CSDN博客

广搜:(BFS)

应用场景:

1.迷宫问题(求最短路径)(图的最短路径)

2.图中的搜索问题(孤岛)。

模板:

我个人觉得用马的遍历这个模板就很经典

DFS和BFS_钟一淼的博客-CSDN博客

注意:

1.BFS运用队列,多数需要定义结构体

2.判断范围条件写好 ,一定得保证它在这一范围区域内进行搜索。

DFS和BFS_钟一淼的博客-CSDN博客

例题1:

寻求最短路径(也可以用Floyd算法求解)

P1135 奇怪的电梯(淼淼总结BFS)_钟一淼的博客-CSDN博客

 例题2:

关于孤岛的问题(面积扩张)典型的图中搜索指定量的做法

P1596 [USACO10OCT]Lake Counting S(DFS)_钟一淼的博客-CSDN博客

还是不停的搜索其他的相同的点,搜过的点标记出来即可。(这里直接将搜索到的水坑直接变成旱地即可)。

二,蓝桥杯的总结:

这周接触了蓝桥杯上面的几个题目,分别说一下学到了什么?

例1:(欧拉定理)

平面的增加=交点分割线段的个数。

蓝桥杯(平面切分)_钟一淼的博客-CSDN博客

注意点:

1.这里用了STL库里的函数set做到了有效去重,减少操作次数。

2.还有就是这里的结构体可以直接用STL里的set<pair<int,int>>来定义会更加方便简洁。 

例2:(动态规划入门)

数字三角形(基础篇):

P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1216

题目分析:就是从下到上不停的更新加上左下值或者加上右下值,谁更大,更优!

状态转移方程: 

a[i][j]=max(a[i-1][j]+a[i-1][j-1])

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int mp[1010][1010];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            cin >> mp[i][j];
        }
    }
    for (int i = n - 1; i > 0; i--) {
        for (int j = 1; j <= i; j++) {
            mp[i][j] += max(mp[i + 1][j], mp[i + 1][j + 1]);//更新最大值
        }
    }
    cout << mp[1][1] << endl;
}

2.进阶版本: 

数字三角形 - 蓝桥云课 (lanqiao.cn)

题目分析:

1.如果说上一个从下面开始向上递归比较简单的话,那这个题目就是向下搜会比较简单。

2.因为这个题必须保证左右方向个数相等,所以就有了图中的两种判别情况。 

代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
int mp[1010][1010];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            cin >> mp[i][j];
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j<=i; j++) {
            mp[i][j]+=max(mp[i - 1][j], mp[i - 1][j - 1]);
        }
    }
    if (n % 2 == 0) {
        cout << max(mp[n][n / 2], mp[n][n / 2 + 1]) << endl;
    }
    else {
        cout << mp[n][n / 2+1] << endl;
    }
}

       动态规划的问题是非常复杂的,介绍的这种也是基础中的基础,持续更新...

三,关于Codefores比赛的总结

 比赛总结:

Codefores CodeTON Round 1 (Div. 1 + Div. 2)比赛总结_钟一淼的博客-CSDN博客

 基本需要注意的点都已经写好了,还是算法的优化和数学思维的掌握吧!

关于STL如何降低复杂度?

Codefores CodeTON Round 1 B题_钟一淼的博客-CSDN博客

        这道题目其实我分析的还是比较透彻的,主要还是我用了两层for循环导致我直接超时,所以说利用了map映射map<int,bool>mp,直接用键值就能返回bool类型判断该数到底存不存在 。

        还可以利用set集合(set<int>v)直接去掉重复值,利用set函数中find()函数,如果存在,就返回该数的下标,如果不存在,就返回最后一个元素迭代器的位置,所以我们这时候的判断条件只需要写if(v.find(value)!=v.end()),则证明该元素存在。

实现代码:

#include <iostream>
#include <set>
using namespace std;
int t;
int n, k;
long long a[260000];
set<int>s;
int main()
{
    cin >> t;
    while (t--) {
        s.clear();
        int flag = 0;
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            s.insert(a[i]);
        }
        for (int i = 1; i <= n; i++) {
            if (s.find(a[i] + k) != s.end()) {
                flag = 1;
                break;
            }
        }
        if (flag != 0) {
            cout << "YES" << endl;
        }
        else {
            cout << "NO" << endl;
        }
    }
}

也可以用vector进行优化:(算是STL的一个广泛应用)

实现代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, m, a;
        cin >> n >> a;
        vector<int> v(n);
        for (int i = 0; i < n; i++) {
            cin >> m;
            v.push_back(m);
        }
        bool ans = false;
        if (n == 1) ans = (v[0] == a);
        else {
            sort(v.begin(), v.end());
            int i = 0;
            int j = 1;
            while (j < n and i < n) {
                if (v[i] + abs(a) == v[j]) {
                    ans = true;
                    break;
                }
                else if (v[i] + abs(a) < v[j]) ++i;
                else ++j;
            }
        }
        if (ans == true) {
            cout << "YSE" << endl;
        }
        else {
            cout << "NO"<<endl;            
        }
    }
}

贪心思想:

总结的一个小题:

Codefores教育代码第125轮C题_钟一淼的博客-CSDN博客

四,周总结

        这周真没学什么很系统的东西,还是主要复习了复习搜索的知识点,练了一些题目,虽然阅读的东西很多,但我总觉得我没有吸收进去,所以这周才更加仔细的推敲某些题目,更加深入的了解,零零碎碎的一些东西就全当是积累了,毕竟数学的内容挺多的,还是需要定时积累的,还有关于codefores比赛的一些问题,数学思维有了,我该如何去实现代码,用最优解,因为codefores比赛中的数据较大,基本到了O(n)以上的复杂度都会被卡,还有就是静下心来多看些资料,把之前的题目总结出来,不断优化算法的时间复杂度,下周更新最小生成树的一些内容,道阻且长。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

钟一淼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值