P1162 填涂颜色
由数字 0 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 1 构成,围圈时只走上下左右 4 个方向。现要求把闭合圈内的所有空间都填写成 2。例如:6×6 的方阵(n=6),涂色前和涂色后的方阵如下:
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数 n(1≤n≤30)。接下来 n 行,由 0 和 1 组成的 n×n 的方阵。方阵内只有一个闭合圈,圈内至少有一个 0。
输出格式
已经填好数字 2 的完整方阵。
#include <bits/stdc++.h> #define MAXN 40 using namespace std; int n; int a[MAXN][MAXN]; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; queue<pair<int,int> >q; void bfs() { while(!q.empty()) { int x=q.front().first; int y=q.front().second; q.pop(); for(int i=0;i<4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(a[x][y]==0&&a[xx][yy]==2) { a[xx][yy]=0; q.push(make_pair(xx,yy)); } } } } int main() { int resx,resy; cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>a[i][j]; if(a[i][j]==0) a[i][j]=2; } } for(int i=1;i<=n;i++) { if(a[1][i]==2) { a[1][i]=0; q.push(make_pair(1,i)); } if(a[n][i]==2) { a[n][i]=0; q.push(make_pair(n,i)); } if(a[i][1]==2) { a[i][1]=0; q.push(make_pair(i,1)); } if(a[i][n]==2) { a[i][n]=0; q.push(make_pair(i,n)); } } bfs(); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) cout<<a[i][j]<<" "; cout<<endl; } return 0; }
这道题的思路就是在遍历的过程中,只要遇到0,就先涂成2,这当中肯定有误涂的,然后我们开始修正。首先边边角角的地方(即第1行、第1列、第n行、第n列)2肯定要涂成0,然后把这些点推入队列里,开始上下左右四个方向广搜。把和这些点相连的2涂成0
P1135 奇怪的电梯
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1≤i≤N)上有一个数字 Ki(0≤ Ki ≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3,3,1,2,5 代表了 Ki(K1=3,K2=3,……),从 1 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入格式
共二行。
第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为 N 个用空格隔开的非负整数,表示 Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出 -1。
#include <bits/stdc++.h> #define MAXN 1005 using namespace std; int a[MAXN]; int vis[MAXN]; int num=1000100,n,s,e,flag; void dfs(int cur,int cnt) { if(cur==e) { flag=1; if(cnt<num) num=cnt; } if(cnt>num) return; //不可能是答案了,回去 vis[cur]=1; if(cur+a[cur]<=n&&!vis[cur+a[cur]]) { dfs(cur+a[cur],cnt+1); } if(cur-a[cur]>=1&&!vis[cur-a[cur]]) { dfs(cur-a[cur],cnt+1); } vis[cur]=0; //要记得回溯,不然会WA两个数据点 return; } int main() { cin>>n>>s>>e; for(int i=1;i<=n;i++) cin>>a[i]; dfs(s,0); if(flag) cout<<num; else cout<<-1; return 0; }#include <bits/stdc++.h> #define MAXN 1005 using namespace std; int a[MAXN]; int vis[MAXN]; int num=1000100,n,s,e,flag; void dfs(int cur,int cnt) { if(cur==e) { flag=1; if(cnt<num) num=cnt; } if(cnt>num) return; //不可能是答案了,回去 vis[cur]=1; if(cur+a[cur]<=n&&!vis[cur+a[cur]]) { dfs(cur+a[cur],cnt+1); } if(cur-a[cur]>=1&&!vis[cur-a[cur]]) { dfs(cur-a[cur],cnt+1); } vis[cur]=0; //要记得回溯,不然会WA两个数据点 return; } int main() { cin>>n>>s>>e; for(int i=1;i<=n;i++) cin>>a[i]; dfs(s,0); if(flag) cout<<num; else cout<<-1; return 0; }
P3958 [NOIP2017 提高组] 奶酪
题目描述
现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。
位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑 到奶酪的上表面去?
输入格式
每个输入文件包含多组数据。
第一行,包含一个正整数 T,代表该输入文件中所含的数据组数。
接下来是 T 组数据,每组数据的格式如下: 第一行包含三个正整数 n,h,r,两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。
接下来的 n 行,每行包含三个整数 x,y,z,两个数之间以一个空格分开,表示空洞球心坐标为
(x,y,z)。
输出格式
T 行,分别对应
T 组数据的答案,如果在第 i 组数据中,Jerry 能从下表面跑到上表面,则输出 Yes,如果不能,则输出 No。
#include <bits/stdc++.h> #define MAXN 1100 using namespace std; struct node { long long x; long long y; long long z; }a[MAXN],tree[MAXN]; int T; bool cmp(node a,node b) { if(a.z!=b.z) return a.z<b.z; return a.x*a.x+a.y*a.y<b.x*b.x+b.y*b.y; } long long dis(long long x1,long long x2,long long y1,long long y2,long long z1,long long z2) { return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1); } int main() { cin>>T; while(T--) { long long n,h,r; cin>>n>>h>>r; int cnt=0; int flag=0; memset(a,0,sizeof(a)); memset(tree,0,sizeof(tree));//以上是初始化 for(int i=1;i<=n;i++) { long long x,y,z; cin>>x>>y>>z; a[i].x=x; a[i].y=y; a[i].z=z; } sort(a+1,a+1+n,cmp);//排序 if(a[1].z>r) cout<<"No"<<endl; else { for(int i=1;i<=n;i++) { if(a[i].z<=r) { ++cnt; tree[cnt].x=a[i].x; tree[cnt].y=a[i].y; tree[cnt].z=a[i].z; } for(int j=1;j<=cnt;j++) { if(dis(a[i].x,tree[j].x,a[i].y,tree[j].y,a[i].z,tree[j].z)<=4*r*r) { ++cnt; tree[cnt].x=a[i].x; tree[cnt].y=a[i].y; tree[cnt].z=a[i].z; break; } } if(tree[cnt].z+r>=h) { flag=1; break; } } if(flag) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } return 0; }
这道题先按照z的大小进行排序,如果z的大小一样再比较x^2+y^2。如果z比半径要小,可以直接存入可行数组。之后的洞和可行数组里的洞相比较,如果它俩之间的距离小于半径,说明这个洞也是可行的,存入可行数组。只要可行数组里有一个洞的z加上半径大于奶酪的高度,说明这个奶酪可以被爬上去。一定一定要注意数据的范围。
P1443 马的遍历
题目描述
有一个 n×m 的棋盘,在某个点 (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n,m,x,y。
输出格式n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 −1)。
#include <bits/stdc++.h> using namespace std; int dx[8]={-1,-2,-2,-1,1,2,2,1}; int dy[8]={2,1,-1,-2,2,1,-1,-2}; queue<pair<int,int> > q; int res[500][500]; int vis[500][500]; int n,m,sx,sy; int main() { cin>>n>>m>>sx>>sy; memset(res,-1,sizeof(res)); memset(vis,0,sizeof(vis)); res[sx][sy]=0; vis[sx][sy]=1; q.push(make_pair(sx,sy)); while(!q.empty()) { int x=q.front().first; int y=q.front().second; q.pop(); for(int i=0;i<8;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&!vis[xx][yy]) { q.push(make_pair(xx,yy)); vis[xx][yy]=1; res[xx][yy]=res[x][y]+1; } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%-5d",res[i][j]); printf("\n"); } return 0; }
这道题让我疑惑的就是搜索方向的问题。思路的话还是一样,只要不出边界,没有搜过,就进行搜索,要记得把步数+1。通过这道题,我还get到了pair的用法