搜索
- 马的遍历(洛谷P1443)
STL大法
pair的应用
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 410;
const int fx[10]={0,2,-2,2,-2,-1,1,-1,1},fy[10]={0,1,1,-1,-1,2,2,-2,-2};//方向
int n,m,stx,sty;
int dis[MAXN][MAXN];
queue<pair<int,int> > Q;//本题不需要担心爆数组,用pair代替有两个数据类型的结构体struct,简便
int main () {
scanf("%d%d%d%d",&n,&m,&stx,&sty);
memset(dis,-1,sizeof dis);//初始化
dis[stx][sty] = 0;
Q.push(make_pair(stx,sty));//第一个点入队
while(Q.size()) {
int x = Q.front().first,y = Q.front().second;
for(register int i = 1,newx,newy;i <= 8; ++i) {
newx = x + fx[i]; newy = y + fy[i];//扩展新点
if(newx >= 1 && newx <= n && newy >= 1 && newy <= m && dis[newx][newy] == -1) {//没有超出棋盘并且没有走过
dis[newx][newy] = dis[x][y] + 1;//标记到达该点的最小步数
Q.push(make_pair(newx,newy));//新点入队
}
}
Q.pop();
}
for(register int i = 1;i <= n; ++i) {
for(register int j = 1;j <= m; ++j)
printf("%-5d", dis[i][j]);//输出,注意格式
puts("");//相当于cout << endl
}
return 0;
}
2.呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1≤i≤N)上有一个数字Ki (0≤K i≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3, 3 ,1 ,2 ,5代表了Ki(K1=3,K2=3,…)从1楼开始。在1楼,按“上”可以到4楼,按“下”是不起作用的,因为没有−2楼。那么,从A楼到B楼至少要按几次按钮呢?
输入
5
1 5
3 3 1 2 5
输出
3
法一:dfs
#include<cstdio>
#include<iostream>
using namespace std;
int n,a,b,ans=0x7ffffff;
int to[205];
bool vis[205];
void dfs(int now,int sum)//now表示当前搜到的楼层,sum表示按钮次数
{
if(now==b) ans=min(ans,sum);
if(sum>ans) return;
vis[now]=1;
//不越界就搜
if(now+to[now]<=n&&!vis[now+to[now]]) dfs(now+to[now],sum+1);
if(now-to[now]>=1&&!vis[now-to[now]]) dfs(now-to[now],sum+1);
vis[now]=0;//回溯
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++) scanf("%d",&to[i]);
vis[a]=1;
dfs(a,0);
if(ans!=0x7ffffff) printf("%d",ans);
else printf("-1");
return 0;
}
法二 :bfs(广度优先搜索,队列)
typedef struct {
int floor; //当前所处的楼层编号
int pushcount; //到达该楼层所经历的步数(按按钮次数)
} QElement;
queue<QElement> q; //定义元素类型为QElement的队列q
int n,a,b;
int s[1000]; //数组s记录每个楼层按按钮后能上下的楼层数
int t[1000]={0}; //数组t记录各个楼层是否已经到达过(已访问过)
int main()
{
QElement e1,e2;
int i;
cin >> n >> a >> b;
for (i=1; i<=n; i++) cin >> s[i];
e1.floor=a;
e1.pushcount=0;
q.push(e1); //初始状态入队:当前楼层为a,按按钮次数为0
t[a]=1; //记录当前楼层已访问过
while (!q.empty()) //当队列不为空时,继续宽度优先搜索
{
e2=q.front(); //获取队头元素
q.pop(); //队头元素出队(注意:c++的队列模板类中,获取队头元素并不会将该元素从队列中删除,需要使用pop函数删除该元素)
if (e2.floor==b) break; //检查当前状态的楼层编号是否为b,是则说明已经找到最终解,跳出循环
i=e2.floor+s[e2.floor]; //按向上按钮后能够到达的楼层
if (i<=n && t[i]==0) //如果按向上按钮能到达的楼层有效并且未访问过该楼层
{
e1.floor=i;
e1.pushcount=e2.pushcount+1;
q.push(e1);
t[i]=1; //设该楼层为已访问过
}
i=e2.floor-s[e2.floor]; //按向下按钮后能够到达的楼层
if (i>=1 && t[i]==0) //如果按向下按钮能到达的楼层有效并且未访问过该楼层
{
e1.floor=i;
e1.pushcount=e2.pushcount+1;
q.push(e1);
t[i]=1; //设该楼层为已访问过
}
}
//如果当前楼层为b,输出按按钮次数,否则无解(输出-1)
if (e2.floor==b) cout << e2.pushcount;
else cout << -1;
}
法三
floyd
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dis[201][201],n,a,b,x;
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
dis[i][j]=dis[j][i]=1e8;
for(register int i=1;i<=n;i++)
{
scanf("%d",&x);
if(i+x<=n) dis[i][i+x]=1;
if(i-x>=1) dis[i][i-x]=1;
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j];
if(dis[a][b]<1e8) printf("%d",dis[a][b]);
else printf("-1");
return 0;
}
法四
spfa(单源最短路径)
#include<bits/stdc++.h>
using namespace std;
const int N=210;
int n,a,b,tot,ver[2*N],head[N],next[2*N],dis[N];
bool vis[N];
queue<int> q;
void add(int x,int y)
{
ver[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void spfa()
{
dis[a]=0;
vis[a]=1;
q.push(a);
while(q.size())
{
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x];i;i=next[i])
{
int y=ver[i];
if(dis[y]>dis[x]+1)
{
dis[y]=dis[x]+1;
if(!vis[y])
{
q.push(y);
vis[y]=1;
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(i+x<=n) add(i,i+x);
if(i-x>=1) add(i,i-x);
}
memset(dis,0x3f3f3f3f,sizeof dis);
spfa();
if(dis[b]<0x3f3f3f3f) printf("%d",dis[b]);
else printf("-1");
return 0;
}