第六周小结

  本周接着看搜索专题,大部分题读过一遍,理解了题意,也试着解题。前面的题比较基础,开始做还有些困难,做的熟练了,速度也就跟了上来。后面的题就难了很多,不再是单纯的深搜广搜,多了些与其他知识点的结合,如二叉树、STL、并查集等。难度加大,做题速度也慢了下来。虽然出的题不算多,但收获不少,在此整理一些我觉得很有收获的题目。

1.P1506 拯救oibh总部.
  这道题题意是给出由‘* ’和‘0’组成的图,求上下左右被‘*’包围的0有多少个。明显是连通块问题,一般的解法是从第一格向最后一格遍历寻找目标点,但是通过浏览题解,我学到了一个从外围向内搜索的方法。
  从外向内搜索的题解.
  根据题意,外围的0没有围墙,水一来就会被淹,所以从外围开始向内圈遍历比从第一格向最后一格遍历要简单许多,而且题解用两个for循环了第1,x行和第1,y列从而达到从外围开始遍历的做法也让我开拓了思路,这对我以后解决类似题有很大帮助。所以有时做题不能僵硬地套用模板,要学会结合题目灵活变通,同时思维要活跃,做题时要常常思考这种方法合适吗?有没有更有的解法?这样不断训练才可能提升我们快速找到最优解的能力。

2 P1030 NOIP2001 普及组 求先序排列.
  这道题为二叉树与搜索结合的题目,题意为根据二叉树的中序与后序排列求出它的先序排列。
  在读题时看到了先序排列等概念,开始对此概念不甚熟悉,后来通过查阅资料也理解了概念,在此将之作为知识点整理一下。

  • 先序排列:先序是先访问树的根节点,再访问树的左子节点,再访问右子节点。
  • 中序排列:中序是先访问树的左子节点,再访问树的根节点,再访问右子节点。
  • 后序排列:后序先访问树的左子节点,再访问树的右子节点,再访问根节点。

思路
  以中序排列ACTRBHFKX,后序排列CARTHXKFB为例,可得B为根节点,ACTR为左子树,HFKX为右子树;
  那么怎么确定子树的结点位置呢?由后序CART得子树的根节点为T,子树的左子树为AC,子树的右子树为R,以此类推,可最终求得明确排序的二叉树,从而求得先序排列。

题解
1.根据后序排列找到根节点;
2.根据中序排列找到左右子树;
3.递归重复1.2步骤找到子树的排列方式。

一点新东西:

  • string类中substr( )函数
    复制子字符串,要求从指定位置开始,并具有指定的长度。
    (用这个函数解题真的嘎嘎快)

核心代码

void dfs(string in,string post)
{ char ch=post[post.size()-1];//ch存放根节点
   cout<<ch;
  int k=in.find(ch);//根节点在中序排列中的位置
  preod(in.substr(0,k),postod.substr(0,k));
  preod(in.substr(k+1),postod.substr(k,in.size()-k-1));//递归左右子树
}
  1. P1341 无序字母对.
      给定N个各不相同的无序字母对,输出一个字典序最小的有(n+1)个字母的字符串使得每个字母对都出现。读题发现是欧拉回路问题。在写题前,我们先理解一下字典序和欧拉回路。
  • 字典序:简单来说就是按照字典中出现的先后顺序进行排序。
  • 欧拉回路:在一个图中,由i点出发,将每个边遍历一次最终到达j点的一条路径叫欧拉路径,i=j时的欧拉路径即为欧拉回路。
  • 判断欧拉路径是否存在:
    无向图:每个点的度数均为偶数。
    有向图:所有点的入度等于出度,就存在一条欧拉回路。
    (参照此博客:欧拉回路/路径【总结】

  知道了这些,我们就可以看题啦。本题实际上就是在找欧拉路经,每个字符可以看做图中的一个点,输入的字符串可以看做两点之间有连通,求输出的字符串实际上就是找输出一笔画回路,至此思路就明了了·。
代码

#include<bits/stdc++.h>
#define N 10010
using namespace std;
int n,m,d[N][N],s1=N,ans;//d是表示两点的连接
char du[N],a[N];//du存度数,a存路径
void search(int i)
{ for(int j=1;j<=150;j++)
  if(d[i][j]>0){d[i][j]--; d[j][i]--; search(j);}
  a[ans]=i;
  ans++;
  return ;
}
int main()
{ cin>>m;
  for(int i=1;i<=m;i++)
   { string s;
     cin>>s;
     d[s[0]][s[1]]++;
     d[s[1]][s[0]]++;
     du[s[0]]++;
     du[s[1]]++;
   }
   int c=0,h=0;
   for(int i=1;i<=150;i++)
    if(du[i]&1) {c++;if(!h)h=i;}
    if(!h)
    for(int i=0;i<150;i++)  if(du[i]){h=i;break;}
    if(c&&c!=2) {cout<<"No Solution";return 0;}
    search(h);
    if(ans<m+1){return 0;}
    for(int i=ans;i>=1;i--) cout<<a[i];
    return 0;
}

4.总结
  这周看了许多搜索题,可谓收获满满。有的题能读懂题意,也有解题的思路,但总是在细节处出错,这点还需要加以改进;有的题比较难,时常会找不到思路,也经历过一道题卡好几天A不出来的煎熬。但更多的是A题之后的满足感和学到新东西的快乐。并且洛谷的题解区是个解答疑惑的好去处,一般遇到的困难都有人在上头讲解,还能接触许多别人的好的做题方法。养成做完题翻翻题解的习惯,开拓一下思维,相信能进步的更快。下周再接再厉!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值