同步发布于My Blog
看到各位dalao都把题解和cf补完了,心里慌得一批,马上gun来补题解总结(〃‘▽’〃)
专题链接
BFS(Breadth-first search):
顾名思义,广度优先搜索即优先各个方向向外扩张,而不是专注于某个方向上的深度(DFS),
既然如此,那么BFS一层一层向外延伸的特点可用于求解最短路问题
下面几道例题调教一下吧( ̄▽ ̄)/
K:Safe Path
大意:给定nm(2<=nm<=2e5)的地图,可上下左右移动,求从S点到F点的最短路,同时地图有若干
怪兽M,其(曼哈顿距离)[]为d(0<=d<=2e5)的点均不可走
分析:如果题目没有怪兽的条件,那么就是一道BFS裸题,除了需要考虑如何存地图(*1).
存在怪兽的情况下,对于每个怪兽如果全部暴力标记不能走的点,那么存在一群怪兽聚在一起
时,会对于某些点进行多次标记的多余操作,直接T.(*2)
解决办法:
(*1)·2e5*2e5二维数组开不下,可以转换为2e5一维数组.
·因为输入数据是字符串,也可以考虑string存图.(STL大法好)
整数的话可以用vector.
(*2)我们回想bfs的性质,如果从每个牛同时开始BFS进行标记,那么某两个牛的重合区域
将只会被其中一只牛标记,那么可以保证整张图每个点最多只被标记一次
代码如下
代码里面把每个点的4个方位最远点存进去是煞笔操作
简洁写法是记录每个怪兽坐标,最后一起丢进queue里面进行BFS即可
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#include <string.h>
using namespace std;
const int maxn = 2e5+5;
string a[maxn];
int n,m,d,sx,sy,fx,fy;
int dir[5]={0,-1,0,1,0};
queue<pair<pair<int,int>,int> > q;
map<pair<int,int>,int> ha;
int main() {
scanf("%d %d %d",&n,&m,&d);
getchar();
for(int i=0;i<n;i++) {
cin>>a[i];
getchar();
}
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(a[i][j]=='S') {
sx=i,sy=j;
}else if(a[i][j]=='F'){
fx=i,fy=j;
}else if(a[i][j]=='M') {
q.push(make_pair(make_pair(i,j),1));
//shabi操作
if(i+d<n) q.push(make_pair(make_pair(i+d,j),1)),ha[make_pair(i+d,j)]=1;
if(i-d>=0) q.push(make_pair(make_pair(i-d,j),1)),ha[make_pair(i-d,j)]=1;
if(j+d<n) q.push(make_pair(make_pair(i,j+d),1)),ha[make_pair(i,j+d)]=1;
if(j-d>=0) q.push(make_pair(make_pair(i,j-d),1)),ha[make_pair(i,j-d)]=1;
ha[make_pair(i,j)]=1;
while(!q.empty()) {
int x=q.front().first.first;
int y=q.front().first.second;
q.pop();
for(int k=-1;k<=1;k++) {
for(int kk=-1;kk<=1;kk++) {
int nx=x+k,ny=y+kk;
if(nx>=0&&nx<n&&ny>=0&&ny<m&&!ha.count(make_pair(nx,ny))&&a[nx][ny]!='M'&&abs(nx-i)+abs(ny-j)<=d) {
//printf("%d %d %d %d\n",nx,ny,i,j);
a[nx][ny]='O';
ha[make_pair(nx,ny)]=1;
q.push(make_pair(make_pair(nx,ny),1));
}
}
}
}
}
}
}
/*
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
cout<<a[i][j];
}
cout<<endl;
}
*/
if(a[sx][sy]=='S'&&a[fx][fy]=='F') {
q.push(make_pair(make_pair(sx,sy),1));
ha[make_pair(sx,sy)]=1;
while(!q.empty()){
int x=q.front().first.first;
int y=q.front().first.second;
int lv=q.front().second;
//cout<<x<<" "<<y<<endl;
q.pop();
for(int i=0;i<4;i++) {
int nx=x+dir[i],ny=y+dir[i+1];
if(nx>=0&&nx<n&&ny>=0&&ny<m&&!ha.count(make_pair(nx,ny))&&a[nx][ny]!='O'&&a[nx][ny]!='M') {
if(a[nx][ny]=='F') {
cout<<lv<<endl;
return 0;
}
ha[make_pair(nx,ny)]=1;
q.push(make_pair(make_pair(nx,ny),lv+1));
}
}
}
cout<<-1<<endl;
}else{
printf("-1\n");
}
return 0;
}
L:Find The Multiple
大意:给定整数n(1<=n<=200),求G=m*n只存在1 or 0,(m<=1e100),输出G(不唯一)
分析:如果按照题意遍历n的倍数 ==> 1e100/1e2=1e98 ==> TLE
反过来想,如果只遍历所有只有1或0的整数,那么约有2^100≈1e30
打表之后发现似乎并不需要这么多,long long就能装下了,不会证明,逃~~
写法:维护一个queue,先push(1),每次取队头x,x*10和x*10+1继续push进去,直到找到
能整除n的整数,输出,结束
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <string.h>
using namespace std;
typedef long long ll;
int n;
queue<ll> q;
int main() {
while(scanf("%d",&n)&&n>0) {
while(!q.empty()) q.pop();
q.push(1);
while(!q.empty()) {
ll u=q.front();
q.pop();
if(u%n==0) {
printf("%lld\n",u);
break;
}
q.push(u*10);
q.push(u*10+1);
}
}
return 0;
}
M:Prime Path
大意:给定一个四位数,每次修改其中一位,求到达一个素数的最短路径
分析:涉及素数,那就先打出素数表
那么可以模拟题意进行BFS,每次取队头,暴力出所有可以换的数字
(注意第一位不能为0),存进队列
代码如下:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e5;
int T,p[maxn],vis[maxn],s,f;
queue<pair<int,int> > q;
void init() {
memset(p,0,sizeof(p));
int m=sqrt(maxn+0.5);
for(int i=2;i<=m;i++) if(!p[i]) {
for(int j=i*i;j<=maxn;j+=i) p[j]=1;//1表示不是_(:з」∠)_
}
}
int fun(int a,int n) {
int u=1;
for(int i=1;i<n;i++) {
a/=10;
u*=10;
}
return a%10*u;
}
int mypow(int x,int y) {
int u=1;
for(int i=1;i<=y;i++) {
u*=x;
}
return u;
}
int main() {
init();
scanf("%d",&T);
while(T--) {
memset(vis,0,sizeof(vis));
scanf("%d %d",&s,&f);
int ok=0;
while(!q.empty()) q.pop();
q.push(make_pair(s,0));
vis[s]=1;
while(!q.empty()) {
int nownum=q.front().first;
int nowlv=q.front().second;
//printf("%d %d\n",nownum,nowlv);
q.pop();
if(nownum==f) {
cout<<nowlv<<endl;
ok=1;
break;
}
for(int i=1;i<=4;i++) {
int c=nownum;
c-=fun(c,i);
//printf("%d %d\n",nownum,c);
for(int j=0;j<=9;j++) {
if(c+j*mypow(10,i-1)>1000&&!vis[c+j*mypow(10,i-1)]&&!p[c+j*mypow(10,i-1)]) {
q.push(make_pair(c+j*mypow(10,i-1),nowlv+1));
vis[c+j*mypow(10,i-1)]=1;
}
}
}
}
if(!ok) {
printf("Impossible\n");
}
}
return 0;
}
DFS(Depth-first search)
深度优先遍历,有别于广度优先,每次搜索都会“一条路走到黑”,可以用于求解
是否存在可行解,配合回溯、剪枝更美味哦Ψ( ̄∀ ̄)Ψ
G:Lake Counting
大意:给定n*m的地图,求w联通块数量,连通的条件是8个方向上有接触.
分析:裸DFS,注意一下标准写法。
代码如下:
#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100;
int ans=0,n,m,vis[maxn][maxn];
char map[maxn][maxn];
int dir[3]={0,-1,1};
int dfs(int x,int y) {
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
int nx=x+dir[i],ny=y+dir[j];
if(nx>=0&&ny>=0&&nx<n&&ny<m&&!vis[nx][ny]&&map[nx][ny]=='W'){
vis[nx][ny]=1;
dfs(nx,ny);
}
}
}
return 0;
}
int main() {
memset(vis,0,sizeof(vis));
scanf("%d %d",&n,&m);
getchar();
for(int i=0;i<n;i++) {
gets(map[i]);
}
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(!vis[i][j]&&map[i][j]=='W') {
ans++;
vis[i][j]=1;
dfs(i,j);
}
}
}
cout<<ans<<endl;
return 0;
}
I:Red and Black
大意:给定N*M的地图,求出起点@能往外走的格子个数
分析:dfs裸题,找到起点,开始dfs递归,标记走过的格子,最后统计一下有多少个
标记即可
代码如下:
#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 50;
int ans=0,n,m,vis[maxn][maxn];
char map[maxn][maxn];
int dir[5]={0,-1,0,1,0};
int dfs(int x,int y) {
for(int i=0;i<4;i++) {
int nx=x+dir[i],ny=y+dir[i+1];
if(nx>=0&&ny>=0&&nx<n&&ny<m&&!vis[nx][ny]&&map[nx][ny]=='.'){
vis[nx][ny]=1;
dfs(nx,ny);
}
}
return 0;
}
int main() {
while(scanf("%d %d",&m,&n)&&n>0&&m>0) {
memset(vis,0,sizeof(vis));
getchar();
for(int i=0;i<n;i++) {
gets(map[i]);
}
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(map[i][j]=='@') {
vis[i][j]=1;
dfs(i,j);
}
}
}
ans=0;
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(vis[i][j]) {
ans++;
}
}
}
cout<<ans<<endl;
}
return 0;
}
H:Sticks
还没补or2
J:AND Graph
同样没做(/ω\)
后记:专题一的简单总结结束,专题二的DP继续加油啊WiLe蒟蒻∠( °ω°)/