2019暑期集训第一周小结

E、剪枝搜索

特点:

一轮搜索完成后,清空标记数组的问题

在搜索的过程中,需要借助标记数组,来防止重复的访问。
之前采取的方法是,通过标记为1,表示该值被访问过。
但是这样做不适合多轮的搜索,因为每轮搜索结束后,都需要重新把标记数组清零。

解决:每轮搜索都设置一个唯一的值(不再局限于1和0)

标记数组的本质是通过设置不同的数字,来区分两块数据。

一个区域里面的所有的点的答案值相同,如何赋值的问题
  1. 通过搜索该区域里面所有的点,得到一个答案。同时,根据题意,这个答案也是同区域里面其他点的答案。因此,希望采用记忆化的思想,当查询其他点时,直接输出答案。

  2. 联想到上一个问题中提到的标记数组,恰好,标记数组具有这样的特性,因为每轮搜索都相当于完成一个区域的查询,因此 通过查询该点的 标记数组所代表的值 ,来判断是否需要重新搜索。

M题

  • 无向图

无向图存边的数组容量开二倍的问题

虽然题目只给出了一条边,但是因为是无向图,所以要正反处理两次,因此存边的数组容量应该开二倍。

  • 链式前向星

B题 特殊的BFS边界条件判断

背景

因为题目要求玩家只要最后可以安全到达最后一列即可,设共有n列,根据题目规则,因为玩家只能走值为“.”的格,且玩家到达第n列,第n+1列,第n+2列都输出“YES”。 因此,如果不对第n+1列,第n+2列做预处理的话,前后条件就发生了冲突。

教训

  • 注意辨别if前后的判断条件是否会有冲突。
  • 想一想地图之外的点如果也是可达点的话,是否需要与地图内的那些可达点统一格式。

C题 构造

题目

有颜色分别为A B C D的四种颜色块,他们之间通过互相交融,使得每种颜色都能有特定数量的联通块。

解题思想

由小及大

  • 先看两个颜色之间
    • 先看两种颜色各形成一个连通块,会是类似于条形磁铁的样子,A全部在左边,B全部在右边,井水不犯河水。
    • 再看要求连通数为 2 1 ,则把一个A放到B中。
  • 发现四个颜色的组合,其实也可以用这种思想。

D题 数学、构造

  • 通过点或边的个数,计算平行四边形的个数。
  • 通过平行四边形的定义,判断怎样搜索可以查询平行四边形的所有组合方式。

这段时间做搜索做的,光想着怎么搜索来找到全部平行四边形的个数,忘记了可以直接用数学方法来计算。

H题 DP之维护最长距离

发现问题的关键,即一个点删除的条件是 到达该点的最长距离是否大于该点的权值,因此应当维护这么一个数组con,con[i]代表到达点i的最长路径的长度。

k叉树 已知结点个数,判断树的深度


//树型结构,已知结点数求完全k叉树的深度


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
typedef long long  LL;
const double pi=acos(-1.0);
const double e=exp(1);
//const int MAXN =2e5+10;
const int N =332748118;

int main()
{
    LL i,p,j,n,t,k;
    LL deep,head,mid,live,two,ans,ceng;
    double ce;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&k,&n);
        if(k == 2 && n == 1)
        {
            ans = 0;
        }
        else
        {
            head = 1;
            mid = 1;
            for(i = 0; i <= 100000; i++)
            {
                ceng = i + 1;  //当前的层数
                if(head == n)        // ceng层的满k叉树
                {
                    ans = i * 2;
                    break;
                }
                else if(head > n)   //  ceng-1层满的k叉树
                {
                    //live = i;
                    //deep = i - 1;

                    //  cout << " ** " << mid << "   ceng :" << ceng << endl;
                    //  cout << " head: " << head << endl;
                    // head - n 少的结点数   判断少于一半
                    if( mid - (head - n)  >  (mid / k) )                // head 当前ceng满k叉树应该有的总结点数
                    {
                        // mid 当前ceng应该有的结点数
                        ans = i * 2;
                    }
                    else
                    {
                        ans = (i - 1) * 2 + 1;
                    }

                    break;
                }

                mid *= k;    // k的ceng次幂
                head += mid;
            }
        }

        printf("%lld
",ans);

    }
    return 0;
}

原文地址:https://www.cnblogs.com/daybreaking/p/12782822.html