搜索专题最后一周我们开始a题了,这周和上两周最大的感触一个是实际写起来和当时看题的感觉真的很不一样,虽然当初看题的时候也是什么都不会,也看了题解然后才慢慢了解,最后好像是看懂了,但是一直到自己开始a题后才意识到什么地方不懂,
一、 首先是搜索类基本题型的转变。一开始我们很容易看出我们做的题都是一些简单的题目,是那种一眼就可以看出怎么做的,一种是对于数的搜索,比如
P1036 [NOIP2002 普及组] 选数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
或者
P1706 全排列问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这一类,还有一种是涉及矩阵的对于图中 点的搜索,
比如:P1451 求细胞数量 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
还有P1506 拯救oibh总部 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)z
等等这些都是相对基础的,让我们入门,然后题目就会开始慢慢提升难度,先是转变了题型,
比如:P1037 [NOIP2002 普及组] 产生数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
不再是简单的无脑搜了,开始加了一些规则,然后我们也能看出,这些题也实际上结合了其他知识点,不再是单纯的搜索了,这就开始考察我们的总结和融合知识的能力了,就像 洛谷P1596 Lake Counting S 因为情况很多就使用了二进制储存每种情况,用二进制转存为十进制,这是子集枚举里的知识点
int erj()
{
int k=0;
for(int i=1;i<=n;i++)
{
k+=a[i]*(1<<(n-i));
}
return k;
}
然后深搜时就将这个代表二进制的十进制数进行操作
void dfs(int x)
{ if(x==(1<<n))
{ for(int j=1;j<=n;j++)
if(vis[x][j]==0) w++;
if(w==n) return ;
}
for(int i=1;i<=n;i++)
{
a[i]?a[i]=0:a[i]=1;
if(flag[erj()]==1)
{
a[i]?a[i]=0:a[i]=1;
continue;
}
flag[erj()]=1;
for(int j=1;j<=n;j++)
{
vis[x][j]=a[j];
}
dfs(x+1);
flag[erj()]=0;
a[i]?a[i]=0:a[i]=1;
}
}
二、和其他知识点算法的结合。a题的时候经常有的感受是明明看的是搜索,又发现和其他自己不会的知识点结合了,又去看那个知识点,然后就慢慢跑偏了。 搜索能结合的知识点其实有很多,感觉应用很广泛,比如:
P3884 [JLOI2009]二叉树问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
就是典型的和二叉树结合,深搜每个结点。
然后是和图论的结合,从之前我们做题时涉及的对图中点的行进搜索就可以看出已经涉及一点图的遍历了,比如P1330 封锁阳光大学 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
就用了图论里改用vector邻接表存储的方法
void dfs(int no, int co)
{
col[no] = co;
vis[no] = 1;
a[co]++;
for (int j = 0; j < vec[no].size(); j++)
{
int next = vec[no][j];
if (vis[next] == 1)
{
if (col[next] != co)
continue;
else
{
flag = 1;
return;
}
}
else
{
int co2;
if (co == 0) co2 = 1;
else co2 = 0;
dfs(next, co2);
}
}
}
还有些应用比较广泛的是并查集,以及拓扑排序等
总结:在做这些题的时候也会发现再学其他知识类似像是图论,二叉树,并查集,拓扑这些知识上的基础的地方都有搜索的影子,也就是说搜索是基础,那么基础就可以和各种不基础的结合。而在做题目的时候遇到有分支选择的,也就是答案不唯一的或者说,选择不唯一的就有可能用到搜索。