蓝桥杯31天冲刺打卡(Day18)超详解

目录

A 找素数

解析:

代码: 

B 分考场

解析:

代码: 

C 合根植物

解析:

代码:

D 大胖子走迷宫

解析:

代码:

A 找素数

解析:

        for循环遍历判定素数,到100002时输出即可(填空题不需要关心时间复杂度)

代码: 

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

bool is_prime(int n) {
	for(int i=2; i<=sqrt(n); i++)
	if(n%i==0) return false;
	return true;
}

int main() {
	int n=0;
	for(int i=2; ; i++) {
		if(is_prime(i)) n++;
		if(n==100002) {
			cout<<i;
			return 0;
		}
	}
	return 0;
}

B 分考场

解析:

        这是一道DFS题,但又不普通,因为它是多源回溯。下面分析一下思路:一个考场中不能坐两个已经认识的人(可能没有监考老师,这样可以有效防止作弊,不过这学校有那么多考场也是挺富裕),题目问至少要分配几个考场。

        这个题乍一看,根本不会,无从下手。深入思考一下:考场是由人数和这些人之间的关系所控制的,假如有n个人,最多当然是n个考场,假设他们每个都不认识,那么至少一个考场就够了(每个考场没上限),除去考场这个待求变量,还有考生这个已知变量,那就只能从这入手了。

        我们先给第一个考生分配考场(考场1),然后需要判定下一名考生是否和第一名认识,不认识就塞到考场1,认识就新分配一个考场2,第三名考生来了!判定一下和第一、第二名是否认识,认识就分配考场3,不认识就相应地分配到对应考场,重点来了(我说的是判定与第一、第二名是否认识,而不是上一名,所以我们需要每次都要重新从第一个考场遍历到当前已有考场)。

        上面这个就是大概的思路,具体解释见代码。

代码: 

#include <bits/stdc++.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int n,m,minn=INF;
int p[105][105],a[105][105];//p指当前课室的座位是否有人,a是存考生间的关系 
//x是第x个考生,ks指第ks个考场(隐喻:已经有了ks个考场) 
void dfs(int x,int ks) {
	if(ks>minn) return;//已经知道最少考场数了,比它大或相等当然出来(小剪枝,只写大于会超时) 
	if(x>n) {//所有考生分配完教室了,unbelievable 
		minn=min(minn,ks);//找出最小值 
		return;
	}
	//从第一个考场遍历 
	for(int i=1; i<=ks; i++) {
		int j=0;//第i个考场第j个座位
		//p[i][j]为不为0说明该座位有人,需要while来查找该考场的空座位;a[p[i][j]][x]说明p[i][j]这名考生和x认识,那么直接退出循环,且不用进入if 
		while(p[i][j] && !a[p[i][j]][x]) j++;                
		//p[i][j]为0说明该位置没人,直接进入if分配位置
		//p[i][j]&&!a[p[i][j]][x]说明位置有人且与x无关,x可以待在这个考场
		//p[i][j]&&a[p[i][j]][x]说明位置有人且与x有关,这个考场x待不得,溜了溜了!看看下个考场(if当然也不用做) 
		if(p[i][j]==0) {//给x分配座位 
			p[i][j]=x;//该座位为空,第i考场第j座位有个考生叫x 
			dfs(x+1,ks);//给下一个小可耐分配位置 
			p[i][j]=0;//回溯,以便后续重新遍历能算出更小值 
		}	 	 
	}
	p[ks+1][0]=x;//已有考场里的人都认识,老师又怕我作弊,那我走还不行吗?我自己开个考场 
	dfs(x+1,ks+1);//检测下一个学生与下一个考场的关系 
	p[ks+1][0]=0;//回溯 
}


int main() {
	cin>>n>>m;
	for(int i=0; i<m; i++) {
		int j,k;
		cin>>j>>k;
		a[j][k]=a[k][j]=1; //无向图关系 
	}
	dfs(1,1);//第一个考生与第一个考场之间不可描述的关系 
	cout<<minn; 
	return 0;
}

C 合根植物

 

解析:

        这是一道并查集模板题,输入中的相关植物放到一个集合中即可,不过要输出有多少棵合根植物,怎么实现?只要是不同集合需要合并的(多一条边),就少一颗,这样从一开始的n*m棵到最后就能得到答案。

代码:

#include <bits/stdc++.h>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int k,n,m,sum;
int f[1000005];
//并查集模板
void init() {
	for(int i=1; i<=n*m; i++)
		f[i]=i;
}
//找父节点
int find(int x) {
	return f[x]==x ? x : f[x]=find(f[x]);
}

void merge(int a,int b) {
	a=find(a),b=find(b);
	if(a!=b) {
		f[a]=b;
		sum--;//这两棵植物需合并,所以少一颗植物
	}
}

int main() {
	cin>>n>>m>>k;
	init();//初始化

	sum=n*m;//共n*m棵合根植物
    
	for(int i=0; i<k; i++) {
		int a,b;
		cin>>a>>b;
		merge(a,b);//合并合根植物
	}

	/*for(int i=1; i<=n*m; i++)
		cout<<f[i]<<endl;*/
	cout<<sum;
	return 0;
}

D 大胖子走迷宫

 

解析:

       这道题做了半小时,debug找了45min(T-T)。结果是输入错了,博主我定义1为起点,结果输入是整个字符串这样输入,这样会导致第二维下标是0,导致答案出错,找了45min,气死我了!!!小伙伴们记得尽量用0做下标,这样可以给自己带来更大的便利。(我这次就是血的教训)

        这是一道BFS题。直接套BFS模板,然后判定条件即可。具体条件:这个胖子会从5变为3再到1,由于胖子体积能为5或3,所以它可能会卡在原地不动,这里需要特判一下。又因为胖子的体积庞大,我们判定边界和墙面的时候需要加上胖子的体积,到这这道题就解完了。

        

代码:

#include <bits/stdc++.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int t,n,k,vis[1005][1005];//体重、行数、变瘦时间标记数组
char mp[400][400];//存图
//上下左右
const int dr[]= {0,0,-1,1};
const int dc[]= {-1,1,0,0};

struct node {
	int x,y,dis;
	node(int x=0,int y=0,int dis=0):x(x),y(y),dis(dis) {}
};

//在迷宫里饿死啦(T_T)
bool inside(int xx, int yy) {
	if(xx+t/2<=n && xx-t/2>0 && yy+t/2<=n && yy-t/2>0) return true;//记得加上大胖子的身材哦!
	else return false;
}

//大胖子吃太多好胖~卡住啦,动不了,只能在迷宫里饿一饿变瘦子
bool check(int xx,int yy) {
	for(int i=xx-t/2; i<=xx+t/2; i++)
		for(int j=yy-t/2; j<=yy+t/2; j++)
			if(mp[i][j]=='*') return false;
	return true;
}
//博主最爱的bfs 
void bfs() {
	queue<node> q;
	node u(3,3,0);//大胖子出发啦
	vis[3][3]=1;
	q.push(u);
	while(!q.empty()) {
		node u=q.front();
		q.pop();
		if(u.x==n-2 && u.y==n-2) {
			cout<<u.dis;
			return;
		}
				
		if(u.dis<k) t=5;//大胖子
		else if(u.dis>=k && u.dis<2*k) t=3;//胖子
		else if(u.dis>=2*k) t=1;//瘦子
		
		if(t!=1) q.push(node(u.x,u.y,u.dis+1));//胖子太胖啦,出不去,只能呆在原地 
		
		for(int i=0; i<4; i++) {
			int nx=u.x+dr[i];
			int ny=u.y+dc[i];
			if(inside(nx,ny) && !vis[nx][ny] && check(nx,ny)) {
				vis[nx][ny]=1;//标记
				int diss=u.dis+1;
				node v(nx,ny,diss);
				q.push(v);
			}
		}
	}
}


int main() {
	cin>>n>>k;
	for(int i=1; i<=n; i++)
	for(int j=1; j<=n; j++)//这里不要直接cin>>mp[i],很容易忽视这个错误,上面解析已经说到
		cin>>mp[i][j];
	bfs();
	return 0;
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_谦言万语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值