目录
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;
}