NEUQ-ACM第六周题解

文章讲述了三种编程题目,分别涉及BFS(广度优先搜索)在电梯楼层到达问题、马的遍历、奶酪问题以及填涂颜色问题中的应用,展示了如何使用BFS解决路径寻找和判断相切的问题。
摘要由CSDN通过智能技术生成

P1135 奇怪的电梯

代码:

#include<bits/stdc++.h>
using namespace std;
int n,a,b,to[205];
bool vis[205];
struct node{int id,step;}x;//id表示楼层号,step表示按钮次数
queue<node> q;
int main()
{
	scanf("%d%d%d",&n,&a,&b);
	for(int i=1;i<=n;i++) scanf("%d",&to[i]);
	q.push((node){a,0});
	while(q.size())
	{
		x=q.front();q.pop();
		if(x.id==b) break;
		if(x.id+to[x.id]<=n&&!vis[x.id+to[x.id]])
		{
			q.push((node){x.id+to[x.id],x.step+1});
			vis[x.id+to[x.id]]=1;
		}
		if(x.id-to[x.id]>=1&&!vis[x.id-to[x.id]])
		{
			q.push((node){x.id-to[x.id],x.step+1});
			vis[x.id-to[x.id]]=1;
		}
	}
	if(x.id==b) printf("%d",x.step);
	else printf("-1");
	return 0;
}

解析:

BFS

P1443 马的遍历

代码:

#include<bits/stdc++.h>
using namespace std;
queue<int>q,q1;
int a[401][401],ans[401][401];
int dx[8]={-2,-2,2,2,1,-1,1,-1};
int dy[8]={-1,1,-1,1,2,-2,-2,2};
int main(){
	memset(ans,-1,sizeof(ans));
	int n,m,startx,starty;
	cin>>n>>m>>startx>>starty;
	q.push(startx);
	q1.push(starty);
	ans[startx][starty]=0;
	a[startx][starty]=1;
	while(!q.empty()){
		for(int i=0;i<8;i++){
			int tx=q.front()+dx[i];
			int ty=q1.front()+dy[i];
			if(tx>0&&tx<=n&&ty>0&&ty<=m&&a[tx][ty]==0){
				a[tx][ty]=1;
				ans[tx][ty]=ans[q.front()][q1.front()]+1;
				q.push(tx);
				q1.push(ty);
			}
		}
		q.pop();
		q1.pop();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			printf("%-5d",ans[i][j]);
		}
		printf("\n");
	}
	return 0;
}

解析:

BFS

P3958 [NOIP2017 提高组] 奶酪

代码:

#include<bits/stdc++.h>
using namespace std;//不加本代码爆零
int f[1001];//并查集
int find(int x){
    if (x!=f[x]) f[x]=find(f[x]);
    return f[x];
}//查找+路径压缩
long long dis(long long x,long long y,long long z,long long x1,long long y1,long long z1){
    return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
}//两点距离公式,注意这里算的是距离平方。
long long x[100001],y[100001],z[100001];
int f1[100001],f2[100001];
//f1记录与顶面相交的洞的序号
//f2记录与底面相交的洞的序号
int main(){
    int t;
    scanf("%d",&t);
    int n,h; 
    long long r;
    for (int i=1;i<=t;i++){
        scanf("%d%d%lld",&n,&h,&r);//long long不开的话...
        int tot1=0;//记录与顶面相交的洞有几个
        int tot2=0;//记录与底面相交的洞有几个
        for (int j=1;j<=n;j++){
          f[j]=j;  //并查集初始化
         }
        for (int j=1;j<=n;j++){
            scanf("%lld%lld%lld",&x[j],&y[j],&z[j]);//long long不开的话...
            if (z[j]+r>=h){//判断这个点是否与顶面相交
                tot1++;
                f1[tot1]=j;
            }
            if (z[j]-r<=0){//判断这个点是否与底面相交
                tot2++;
                f2[tot2]=j;
            }
            for (int k=1;k<=j;k++){//枚举之前的洞是否与这个洞相交,如果相交则合并集合
            	if ((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])>4*r*r) continue;
            	//防止爆long long的特判。 
                if (dis(x[j],y[j],z[j],x[k],y[k],z[k])<=4*r*r){
                    int a1=find(j);
                    int a2=find(k);
                    if (a1!=a2) f[a1]=a2;
                }
            }
        }
        int s=0;
        //看看每一个中是否有洞连接上下面
        for (int j=1;j<=tot1;j++){
            for (int k=1;k<=tot2;k++){
                if (find(f1[j])==find(f2[k])){
                    s=1; 
                    break;
                }
            }
            if (s==1) break;
        }
        if (s==1) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 

 解析:

BFS,用一个函数判断是否相切

P1162 填涂颜色

代码:

#include<iostream>
#include<queue>
using namespace std;
int n,xn[4]= {0,1,0,-1},yn[4]= {1,0,-1,0};
int a[32][32];
queue<pair<int,int> >q;//pair队列存坐标
int main() {
	/*
	先把所有的0染成2
	再把闭合环之外的2染回0
	bfs*/
	cin>>n;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			cin>>a[i][j];
		}
	}
	for(int i=0; i<=n+1/*从0赋值到n+1,将外圈和其他0赋值为2*/; i++) {
		for(int j=0; j<=n+1; j++) {
			if(a[i][j]==0)a[i][j]=2;
		}
	}
	q.push(make_pair(0,0));
	while(!q.empty()) {
		int x=q.front().first,y=q.front().second;
		q.pop();
		a[x][y]=0;//赋值为0,改写
		for(int i=0; i<4; i++) {
			if(a[x+xn[i]][y+yn[i]]==2) {//搜索还是2的相邻格子
				q.push(make_pair(x+xn[i],y+yn[i]));
			}
		}
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {/*从1输出到n,别把辅助外圈一块输出了*/
			cout<<a[i][j]<<' ';
		}
		cout<<endl;
	}
}

解析:

将图用一圈0包裹,从最外面的0开始搜索,把没搜到的变为2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值