BFS搜索以及DFS搜索都需要把扩展的节点限制在给定的范围内,否则可能RE
题意:一位傲娇首相要换门牌号。门牌号是四位数字,给定起始门牌号和终止门牌号,每次只能改变一位数字,并且改完必须仍为素数,问需要改变几次?
找最少的一般都是BFS鸭
注意不能用优先权队列,因为有可能要换成小的,也有可能要换成大的
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=9999+10;
int d[5];
int prime[maxn];
bool vis[maxn];
struct point
{
int x;
int time;
};
point start,end2;
bool is_prime(int x)
{
for(int i=2;i<=sqrt(x*1.0);i++)
{
if(x%i==0)
return false;
}
return true;
}
void init()
{
for(int i=1000;i<=maxn;i++)
prime[i]=i;
for(int i=1000;i<=maxn;i++)
{
if(is_prime(prime[i]))
prime[i]=1;
else
prime[i]=0;
}
}
int bfs()
{
queue<point>q;
point old,current;
q.push(start);
vis[start.x]=1;
while(!q.empty())
{
old=q.front();
q.pop();
if(old.x==end2.x)
return old.time;
d[1]=old.x%10;
d[2]=old.x/10%10;
d[3]=old.x/100%10;
d[4]=old.x/1000;
//printf("%d %d %d %d\n",d[4],d[3],d[2],d[1]);
for(int i=1;i<=4;++i)
{
for(int j=0;j<=9;++j)
{
if(i==4&&j==0) continue;
if(i==1&&!(j&1)) continue;
int tmp=d[i];
d[i]=j;
current.x=d[4]*1000+d[3]*100+d[2]*10+d[1];
if(prime[current.x]&&!vis[current.x])
{
current.time=old.time+1;
vis[current.x]=1;
q.push(current);
}
d[i]=tmp; //注意必须要改回来
}
}
}
return -1;
}
int main()
{
//freopen("out2.txt","w",stdout);
memset(prime,0,sizeof(prime));
int T;
scanf("%d",&T);
init();
while(T--)
{
memset(vis,false,sizeof(vis));
scanf("%d %d",&start.x,&end2.x);
start.time=0;
int ans=bfs();
//printf("nas:%d\n",ans);
if(ans!=-1)
printf("%d\n",ans);
else
printf("Impossible\n");
}
return 0;
}
有两种状态转移的方式到达点X,求最短路 没有边权的时候用bfs 白皮:边权都相等的时候可以用广搜,这种情况下,priority_queue 和queue有相同效果,复杂度会发生变化
题意:农夫John站在X点,牛在K点,牛不动,农夫去抓他。一分钟内农夫可移动到X-1,X+1或者2*X,他需要多久能抓住牛?
我以为是个dp_(:з」∠)_
需要注意的是:不加合理范围判断的话会RE。
//A
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
const int NN=1e5+10;
int N,K;
bool vis[NN];
struct Node
{
int x,flag;
}p1,p2;
queue<Node>q;
int bfs(int x) //开始的起点
{
memset(vis,false,sizeof(vis));
p1.x=x,p1.flag=0;
q.push(p1);
vis[p1.x]=true;
while(!q.empty())
{
p2=q.front();
q.pop();
if(p2.x==K) return p2.flag;
else
{
//vis[p2.x]=true; //取出来就标记为访问过
Node tmp;
tmp.x=p2.x+1; tmp.flag=p2.flag+1;
if(tmp.x>=0&&tmp.x<=100000&&!vis[tmp.x]) {q.push(tmp);vis[tmp.x]=true;} //不加范围的话会一直RE
tmp.x=p2.x-1; tmp.flag=p2.flag+1;
if(tmp.x>=0&&tmp.x<=100000&&!vis[tmp.x]) {q.push(tmp);vis[tmp.x]=true;}
tmp.x=p2.x+p2.x; tmp.flag=p2.flag+1;
if(tmp.x>=0&&tmp.x<=100000&&!vis[tmp.x]) {q.push(tmp);vis[tmp.x]=true;}
}
}
}
int main()
{
cin>>N>>K;
cout<<bfs(N)<<endl;
return 0;
}
题意:女主在原点,即将来一批陨石雨,她想去一个不会有陨石砸下来的地方。陨石在时间落在,会同时砸坏四个方向上的相邻土地,女主每单位时间可以移动到周围四个方向上没被砸坏的地方。问女主需要多久到达安全位置。
//https://www.cnblogs.com/iswoit/p/4446543.html
#include<iostream>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=800;
int time[N][N];//最早被炸的时间 //单独开了个数组存安全时间
int vis[N][N];
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int m;
struct node
{
int x,y,t; //这里的t是它在遍历过程中是第几个,代表它的时间为几 我在遍历的过程中需要传递第几层访问这个量,用的结构体存
node(int xx,int yy,int tt) :x(xx),y(yy),t(tt){}
node(){}
};
bool inside(int x,int y)
{
return x>=0&&y>=0;
}
bool safe(int x,int y,int t)
{
if(t<time[x][y]) return true;
else return false;
}
int bfs()
{
queue<node> q;
q.push(node(0,0,0));
while(!q.empty())
{
node tmp=q.front();
q.pop();
int nx=tmp.x;
int ny=tmp.y;
if(vis[nx][ny]) continue;
vis[nx][ny]=true;
if(time[nx][ny]==INF) return tmp.t; //到达安全地点
else
{
for(int i=0;i<4;++i)
{
int nx=tmp.x+dir[i][0];
int ny=tmp.y+dir[i][1];
if(safe(nx,ny,tmp.t+1)&&inside(nx,ny)&&!vis[nx][ny])
q.push(node(nx,ny,tmp.t+1));
}
}
}
return -1; //遍历完了没答案
}
int main()
{
cin>>m;
memset(vis,0,sizeof(vis));
for(int i=0;i<N;++i)
for(int j=0;j<N;++j)
{
time[i][j]=INF;
}
while(m--)
{
int x,y,t;
cin>>x>>y>>t;
time[x][y]=min(time[x][y],t);
//cout<<"?"<<endl;
for(int i=0;i<4;++i)
{
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(inside(nx,ny))//忘记写这个导致越界异常终止一次
time[nx][ny]=min(time[nx][ny],t);
}
}
if(time[0][0]==0) cout<<-1<<endl;
else cout<<bfs()<<endl;
return 0;
}
这道题没拿下。。。LRJ上有源码,我明天再debug
倒水量指的是中间过程,注意注意,倒水过程中要么把i杯倒空,要么把j杯倒满