首先是对搜索的一点新的感悟,在写了几周的搜索题仍然没有任何发现和提升的情况下,果不其然在新星杯上,因为一道比较开门见山的搜索题耽误了大量时间,因祸得福可以有由自己亲手思考亲手做出来,话不多说,先上题
一开始,我想到了全排列,或者说排列组合,可是别说全排列光情况就有几万几十万种,就是排列组合我也只能通过数学的思维描述无法做到用代码将他们列出来再进行保存;
所以我将思路转换到了搜索上面,对n次操作进行搜索,像树一样的结构就是搜索的本体。所以大体我的想法就是在dfs函数里并行三种情况,进行搜索和回溯操作,此时我的脑中已经大致有了想法但是受限于对搜索的熟练度较低,我辗转了许久才写出一个ac的答案。(会写了之后又忘记了回溯)
上一下代码吧
#include<bits/stdc++.h>
using namespace std;
int k,d,a,sum,ans;
void dfs(int x,int y,int z){
if(x==k&&y==d&&z==a){
if(sum==25)
ans++;
return;
}
else{
if(x<k){
int p=sum;
sum+=5;
if(sum>25)
sum=25;
dfs(x+1,y,z);
sum=p;
}
if(y<d){
int p=sum;
sum-=10;
if(sum<0)
sum=0;
dfs(x,y+1,z);
sum=p;
}
if(z<a){
int p=sum;
sum+=2;
if(sum>25)
sum=25;
dfs(x,y,z+1);
sum=p;
}
}
}
int main () {
cin>>k>>d>>a;
dfs(0,0,0);
cout<<ans;
}
dfs到这,现在借用一下大佬的理解作为下周的学习目标吧
/************************************************************
广度优先搜索算法的基本思想:
1、对于初始状态入队,设置初始状态为已访问
2、如果队列不为空时,出队队头元素,否则跳到第5步
3、检查出队的元素是否为最终解,如果是则跳到第5步。
4、对于出队的元素,检查所有相邻状态,如果有效并且未访问,则将
所有有效的相邻状态进行入队,并且设置这些状态为已访问,然后
跳到第2步重复执行
5、检查最后出队的元素是否为最终解,如果是输出结果,否则说明无解
广度优先搜索是借助于队列这种数据结构进行搜索的,队列的特点是先
进先出(FIFO),通过包含queue这个队列模板头文件,就可以利用c++
的队列模板定义自己的队列了,队列的操作非常简单,主要有以下几个:
q.push() 入队操作
q.front() 取队头元素
q.pop() 队头元素出队
q.size() 获取队列的元素个数
q.empty() 判断队列是否为空,为空返回true,不为空返回false
广度优先搜索算法的关键是要搞清楚求解过程中每一步的相邻状态有哪些,
每个状态需要记录什么信息,在搜索过程中如何标记这些状态为已访问。
在本题中,相邻状态为当前所在楼层通过按向上或向下按钮所能到达的楼
层,每个状态要记录的信息包括楼层编号和按按钮的次数。
*************************************************************/
然后是这周的第二个收获吧——链表;
虽然之前已经学过但是无论是理解还是各种形式的循环链表,双向链表都不是很拿手,这周算是一次巩固和复习;(尤其是对于数组模拟链表的运用优势和结构体链表的不同)
上一题我觉得对我最有帮助的题吧,对于数组模拟的开荒题;
#include<stdio.h>
struct node {
int data;
int next;
} p[100001];
int main() {
int i,j,k=0,l,x,one,n,dizhi,nextdizhi;
int add1[100001];
int add2[100001];
scanf("%d %d",&one,&n);
for(i=0;i<n;i++){
scanf("%d %d %d",&dizhi,&x,&nextdizhi);
p[dizhi].data=x;
p[dizhi].next=nextdizhi;
}
while(one!=-1){
add1[k++]=one;
one=p[one].next;
}
l=k;
k=0;
for(i=0,j=l-1;i<=j;){
if(i==j){
add2[k]=add1[i];
break;
}
else{
add2[k++]=add1[j--];
add2[k++]=add1[i++];
}
}
for(i=0;i<l-1;i++){
printf("%05d %d %05d\n",add2[i],p[add2[i]].data,add2[i+1]);
}
printf("%05d %d -1\n",add2[i],p[add2[i]].data);
}
用下标作为地址,两个子数分别为数据和“链”连着下个地址,用数组通过“链“遍历将地址存放在更易更改的小数组中进行操作;
贴题bfs就到这里了吧,下周的学习目标和复习题:
#include<iostream>//P1443
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={2,1,-1,-2,2,1,-1,-2};//8个方向
queue<pair<int,int> > q;
int f[500][500];//存步数
bool vis[500][500];//走没走过
int main()
{
int n,m,x,y;
memset(f,-1,sizeof(f));memset(vis,false,sizeof(vis));
cin>>n>>m>>x>>y;
f[x][y]=0;vis[x][y]=true;q.push(make_pair(x,y));
while(!q.empty())
{
int xx=q.front().first,yy=q.front().second;q.pop();//取队首并出队
for(int i=0;i<8;i++)
{
int u=xx+dx[i],v=yy+dy[i];
if(u<1||u>n||v<1||v>m||vis[u][v])continue;//出界或走过就不走
vis[u][v]=true;q.push(make_pair(u,v));f[u][v]=f[xx][yy]+1;
}
}
for(int i=1;i<=n;i++)
{for(int j=1;j<=m;j++)printf("%-5d",f[i][j]);printf("\n");}//注意场宽!!
return 0;
}