上周讲了栈、队列、DFS、BFS。
有些同学会感到困难,所以对的讲解资料进行推荐。
栈和队列:看PPT就行了,主要理解思想及运用。
DFS,BFS:DFS要深刻理解递归和状态表达,BFS想通状态的层次以及在求一些最小步数、最短路径的题目中运用。
这方面资料除了PPT,还看一下《挑战程序设计竞赛》 这书中的2.1节(P26)和《算法竞赛入门经典》第一版的4.3节(P62)
这两本书在群共享里面都有。
这几个东西一定要理解透彻,后面还会开专题集中训练基础搜索的。
题解:
A、
题意:1~n顺序进栈,然后给一个序列,判断是否是可能的出栈顺序。
思路:按照给出的出栈顺序,一个一个和和当前栈顶的元素比较,不相等就向当前栈压入一个元素,因为是按照顺序压栈的,所以总会找到一个当前给出的顺序所在位置值一样的栈顶元素,然后出栈。同时 给出的元素顺序也后移一位 直到给出的顺序遍历完 或者出错。
参考code:
#include<stdio.h>
int main()
{
int a[1005],b[1005],i,j,k,n;
while(scanf("%d",&n),n)
{
while(scanf("%d",&b[0]),b[0])
{
for(j=1; j<n; j++)
scanf("%d",&b[j]);
for(i=1,j=0,k=0; i<=n&&j<n; i++,k++)
{
a[k]=i;
while(a[k]==b[j])
{
if(k>0)k--;
else
{
a[k]=0,k--;
}
j++;
if(k==-1)break;
}
}
if(j==n)printf("Yes\n");
else printf("No\n");
}
printf("\n");
}
}
B、
题意:对于一个X,支持三种变化:2*X,X-1,X+1。给出A,B 问至少多少步可以从A变成B
思路:很明显的一个BFS题目,挨着搜索一下,并且记录步数。对于搜索范围内设置一个访问数组,已经搜索过的就没必要再从这里搜索了。
参考code:
#include<stdio.h>
#include<climits>
#include<algorithm>
#include<stack>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<string.h>
using namespace std;
int n,k;
int ma=100000;
int vis[100010];
int ret[100010];
int bfs(int n,int k)
{
if(n==k)
return 0;
queue<int> q;
q.push(n);
int cur;
vis[n]=1;
while(!q.empty())
{
cur=q.front();
if(cur==k) break;
q.pop();
if(cur+1<=100000&&!vis[cur+1])
{
vis[cur+1]=1;
ret[cur+1]=ret[cur]+1;
q.push(cur+1);
}
if(cur-1>=0&&!vis[cur-1])
{
vis[cur-1]=1;
ret[cur-1]=ret[cur]+1;
q.push(cur-1);
}
if(cur*2<=100000&&!vis[cur*2])
{
vis[cur*2]=1;
ret[cur*2]=ret[cur]+1;
q.push(cur*2);
}
}
return ret[k];
}
int main(void)
{
while(cin>>n>>k)
{
ma=100000;
memset(vis,0,sizeof(vis));
memset(ret,0,sizeof(ret));
cout<<bfs(n,k)<<endl;
}
return 0;
}
C、
题意:一个棋盘,给出起始坐标和终点左边。需要输出一个最小从起点到终点的方案和步数。
思路:这个题目放在这里,就是让你们坑在固定思维。这道题完全可以不用搜索,直接模拟一下就行了。
参考code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <limits>
#include <map>
using namespace std;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define F(i, n) for(int (i)=0;(i)<(n);++(i))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))
#define MEM0(addr) memset((addr), 0, sizeof((addr)))
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define MAXN 100000
#define MAXM 10000
#define MOD 1000000007
typedef long long LL;
const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;
char a[5],b[5];
int main()
{
int l,c;
while(cin>>a>>b)
{
char m,n;
l=a[0]-b[0];
c=a[1]-b[1];
if(l<0)
{
l=-l;
m='R';
}
else
m='L';
if(c<0)
{
c=-c;
n='U';
}
else
n='D';
printf("%d\n",max(l,c));
while(l|c)
{
if(l)
{
putchar(m);
l--;
}
if(c)
{
putchar(n);
c--;
}
printf("\n");
}
}
return 0;
}
D题:强行灌水的。不说了。
E、
题意:就是找出油田中的联通的块数,相邻指的周围的8个位置。
思路:就是一个DFS,详细见代码。这个是DFS的入门例题。
参考code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
using namespace std;
const int mxn = (int)105;
int n, m, ans;
int u[] = {-1, -1, -1, 0, 0, 1, 1, 1}, v[] = {-1, 0, 1, -1, 1, -1, 0, 1};
char a[mxn][mxn];
int inb(int x, int y) {
return (x < 0 || x >= n || y < 0 || y >= m)? 0: 1;
}
void dfs(int x, int y) {
a[x][y] = '*';
for (int i = 0; i < 8; i++) {
int X = x + u[i], Y = y + v[i];
if (!inb(X, Y) || a[X][Y] == '*') continue;
dfs(X, Y);
}
}
int main() {
while (~scanf("%d %d", &n, &m) && n) {
ans = 0;
for (int i = 0; i < n; i++) {
scanf("%s", a[i]);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == '@') {
ans++;
dfs(i, j);
}
}
}
printf("%d\n", ans);
}
return 0;
}
F、
题意:给一个数n,求出一个只由0,1组成的十进制数,使n能整除这个数。
思路:范围不大。搜索一下,看代码比较容易懂。
参考code:
#include<iostream>
#include<cstdio>
using namespace std;
bool flag;
void DFS(unsigned __int64 t ,int n,int k)
{
if(flag)
return;
if(t%n==0)
{
printf("%I64u\n",t);
flag=true;
return;
}
if(k==19)
return;
DFS(t*10,n,k+1);
DFS(t*10+1,n,k+1);
}
int main()
{
int n;
while(cin>>n,n)
{
flag=false;
DFS(1,n,0);
}
return 0;
}