小白要跟kuangbin大佬刷题嗷~~
下面是用到BFS的题,持续更新?
poj 3278 catch that cow
思路较简单,纯板子题 ,直接上代码
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int dir[2]={-1,1};
int vis[100003];//标记是否之前访问过
int n,k;
struct node
{
int pos;
int step;
};
bool check(int pos)
{
if(pos<0||pos>100003)
return false;
else
if(vis[pos]==1)
return false;
return true;
}
int bfs()
{
node start,next;
queue<node>q;
start.pos=n;
start.step=0;
q.push(start);
while(!q.empty())
{
node tmp=q.front();
q.pop();
if(tmp.pos==k)
return tmp.step;
for(int i=0;i<3;i++)
{
next=tmp;
if(i!=2)
next.pos+=dir[i];
else
next.pos*=2;
if(check(next.pos))
{
next.step++;
vis[next.pos]=1;
q.push(next);
}
}
}
}
int main()
{
cin>>n>>k;
memset(vis,0,sizeof(vis));
int ans=bfs();
cout<<ans<<endl;
}
poj 1426 Find The Multiple
读题真的很重要啊,不不不,是英语真的很重要啊!!!
题意是说找一个只由0,1组成的十进制数能够把n除尽,答案有很多,写出一个就可以。题中给出m的位数不大于100,然而我用 long long 试了试也是可以的emm
用bfs搜就可以,不过每次不符合要求的时候要在队列中push两个数,一个是tmp乘以10,另一个是tmp乘以10+1
#include <iostream>
#include <queue>
using namespace std;
typedef long long int ll;
void bfs(int n)
{
queue<ll>q;
q.push(1);
while(!q.empty())
{
ll tmp=q.front();
q.pop();
if(tmp%n==0)
{
cout<<tmp<<endl;
return;
}
q.push(tmp*10);
q.push(tmp*10+1);
}
}
int main()
{
int n;
while(cin>>n&&n)
{
bfs(n);
}
}
poj 3126 Prime Path
题目大意:将一个素数变成另一个素数最少需要多少步,其中每次只能改变四位数中的一个数,并且得到的每一个数都必须是素数。
这道题问到“最少多少步”,因此选择BFS来解。首先用埃氏筛将素数筛出来
(埃氏筛:要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。)
然后依次改变四位数中的每一位,通过队列来实现BFS
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int a,b;
int isprime[10002];
int vis[10000];
struct node
{
int num;
int step;
};
int bfs()
{
queue<node>q;
node start;
start.num=a;
start.step=0;
q.push(start);
while(!q.empty())
{
node tmp=q.front();
q.pop();
if(tmp.num==b)
return tmp.step;
vis[tmp.num]=1;
for(int i=0;i<=9;i++)//个位
{
node next=tmp;
int p=tmp.num/10*10+i;
if(!isprime[p]&&!vis[p])
{
next.num=p;
next.step++;
q.push(next);
}
}
for(int i=0;i<=9;i++)//十位
{
node next=tmp;
int p=tmp.num%10+tmp.num/100*100+i*10;
if(!isprime[p]&&!vis[p])
{
next.num=p;
next.step++;
q.push(next);
}
}
for(int i=0;i<=9;i++)//百位
{
node next=tmp;
int p=tmp.num%100+tmp.num/1000*1000+i*100;
if(!isprime[p]&&!vis[p])
{
next.num=p;
next.step++;
q.push(next);
}
}
for(int i=1;i<=9;i++)//千位
{
node next=tmp;
int p=tmp.num%1000+i*1000;
if(!isprime[p]&&!vis[p])
{
next.num=p;
next.step++;
q.push(next);
}
}
}
return -1;
}
int main()
{
memset(isprime,0,sizeof(isprime));
for(int i=2;i*i<10002;i++)
{
if(!isprime[i])
{
for(int j=2*i;j<10002;j+=i)
isprime[j]=1;
}
}
int n;
cin>>n;
while(n--)
{
memset(vis,0,sizeof(vis));
cin>>a>>b;
if(a==b)
cout<<0<<endl;
else
{
int ans=bfs();
if(ans==-1)
cout<<"Impossible"<<endl;
else
cout<<ans<<endl;
}
}
}
poj 3414 Pots
此题是阿伟自己写出来的hhhhh~~~(咳咳,表示下开心)
题目大意:给你两个容器,然后对这两个容器有三种操作:
1.FILL(i) 将第i个容器装满(i=1,2)
2.DROP(i) 将第i个容器里的水倒光
3.POUR(i,j) 将i中的水倒入j中,会有两种结果,i容器变空,或者j容器装满
题目给出两个容器的容量以及目标水量(两个容器中任意一个到达目标水量都算完成任务),计算出最少的操作数,使得达到目标水量,并把流程写出来,如果达不到,则输出impossible
题解:本题是说最少的操作数,所以我用的BFS,然而需要将操作流程也要记录下来,这个就比较麻烦,由于操作流程总共只有6种,因此可以用1-6来分别代表操作数,将操作流程以字符串的形式存在结构体中,最后对字符串挨个读取,对应相应的操作就可以了。
这道题的循环还有check都比较麻烦,我用了switch分情况,还有就是BFS核心内容一定不能忘,尤其是先后顺序。
贴上AC代码,嘿嘿嘿~
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int a,b,c;
int vis[101][101];
struct node
{
int one;
int two;
string step;
};
bool check(int t,node tmp,node next)
{
switch (t)
{
case 1:
if(tmp.one>=a||vis[next.one][next.two])
return false;
break;
case 2:
if(tmp.two>=b||vis[next.one][next.two])
return false;
break;
case 3:
if(tmp.one<=0||vis[next.one][next.two])
return false;
break;
case 4:
if(tmp.two<=0||vis[next.one][next.two])
return false;
break;
case 5:
if(tmp.one<=0||tmp.two>=b||vis[next.one][next.two])
return false;
break;
case 6:
if(tmp.two<=0||tmp.one>=a||vis[next.one][next.two])
return false;
break;
}
return true;
}
string bfs()
{
queue<node>q;
node start,next;
start.one=0;
start.two=0;
start.step="";
vis[0][0]=1;
q.push(start);
while(!q.empty())
{
node tmp=q.front();
q.pop();
if(tmp.one==c||tmp.two==c)
return tmp.step;
for(int i=1;i<=6;i++)
{
next=tmp;
switch (i)
{
case 1:
next.one=a;
if(check(i,tmp,next))
{
next.step+='1';
q.push(next);
vis[next.one][next.two]=1;
}
break;
case 2:
next.two=b;
if(check(i,tmp,next))
{
next.step+='2';
q.push(next);
vis[next.one][next.two]=1;
}
break;
case 3:
next.one=0;
if(check(i,tmp,next))
{
next.step+='3';
q.push(next);
vis[next.one][next.two]=1;
}
break;
case 4:
next.two=0;
if(check(i,tmp,next))
{
next.step+='4';
q.push(next);
vis[next.one][next.two]=1;
}
break;
case 5:
if(next.one+next.two>b)
{
next.one=next.one+next.two-b;
next.two=b;
}
else
{
next.two+=next.one;
next.one=0;
}
if(check(i,tmp,next))
{
next.step+='5';
q.push(next);
vis[next.one][next.two]=1;
}
break;
case 6:
if(next.one+next.two>a)
{
next.two=next.one+next.two-a;
next.one=a;
}
else
{
next.one+=next.two;
next.two=0;
}
if(check(i,tmp,next))
{
next.step+='6';
q.push(next);
vis[next.one][next.two]=1;
}
break;
}
}
}
return "-1";
}
int main()
{
memset(vis,0,sizeof(vis));
cin>>a>>b>>c;
string ans=bfs();
if(ans=="-1")
cout<<"impossible"<<endl;
else
{
int len=ans.length();
cout<<len<<endl;
for(int i=0;i<len;i++)
{
switch (ans[i]-'0')
{
case 1:
cout<<"FILL(1)"<<endl;
break;
case 2:
cout<<"FILL(2)"<<endl;
break;
case 3:
cout<<"DROP(1)"<<endl;
break;
case 4:
cout<<"DROP(2)"<<endl;
break;
case 5:
cout<<"POUR(1,2)"<<endl;
break;
case 6:
cout<<"POUR(2,1)"<<endl;
break;
}
}
}
}
hdoj 1495 非常可乐
此题和上一题差不多,都是倒水问题,刚开始怎么都读不懂题 (可能是我语文不太好),看了大佬的题解之后才了解题意。。
题目大意: 有一瓶可乐和两个给定容量的杯子(没有刻度),问如何倒水才能让三个容器中的两个平分这瓶可乐,如果可以写出操作次数,不可以输出“NO”
题解: 刚开始不怎么理解“没有刻度”,还以为倒水的人很牛逼,知道到多少算是可以了。。后来才知道,如果没有刻度的话,只能将一个杯子倒满,或者将另一个杯子倒空,只有这样才能知道所倒水的具体容积,这个操作和上一题的“POUR(i,j) ”操作是一样的,本题枚举6种倒法,然后挨个检查,具体思路和上一题差不多,还要注意一点,当可乐的体积是奇数的时候,肯定不能平分,在这个地方可以剪枝。
上代码!
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int s,n,m;
int vis[101][101][101];
struct node
{
int s;
int n;
int m;
int step;
};
bool check(int t,node tmp,node next)
{
switch (t)
{
case 1:
if(tmp.s<=0||tmp.n>=n||vis[next.s][next.n][next.m])
return false;
break;
case 2:
if(tmp.s<=0||tmp.m>=m||vis[next.s][next.n][next.m])
return false;
break;
case 3:
if(tmp.n<=0||tmp.s>=s||vis[next.s][next.n][next.m])
return false;
break;
case 4:
if(tmp.n<=0||tmp.m>=m||vis[next.s][next.n][next.m])
return false;
break;
case 5:
if(tmp.m<=0||tmp.s>=s||vis[next.s][next.n][next.m])
return false;
break;
case 6:
if(tmp.m<=0||tmp.n>=n||vis[next.s][next.n][next.m])
return false;
break;
}
return true;
}
int bfs()
{
node start,next;
start.s=s;
start.n=0;
start.m=0;
start.step=0;
vis[s][0][0]=1;
queue<node>q;
q.push(start);
while(!q.empty())
{
node tmp=q.front();
q.pop();
if((tmp.s==0&&(tmp.m==tmp.n))||(tmp.m==0&&tmp.s==tmp.n)||(tmp.n==0&&tmp.s==tmp.m))
return tmp.step;
for(int i=1;i<=6;i++)
{
next=tmp;
switch (i)
{
case 1://s->n
if(next.s+next.n>n)
{
next.s=next.s+next.n-n;
next.n=n;
}
else
{
next.n+=next.s;
next.s=0;
}
break;
case 2://s->m
if(next.s+next.m>m)
{
next.s=next.s+next.m-m;
next.m=m;
}
else
{
next.m+=next.s;
next.s=0;
}
break;
case 3://n->s
if(next.s+next.n>s)
{
next.n=next.s+next.n-s;
next.s=s;
}
else
{
next.s+=next.n;
next.n=0;
}
break;
case 4://n->m
if(next.n+next.m>m)
{
next.n=next.n+next.m-m;
next.m=m;
}
else
{
next.m+=next.n;
next.n=0;
}
break;
case 5://m->s
if(next.s+next.m>s)
{
next.m=next.s+next.m-s;
next.s=s;
}
else
{
next.s+=next.m;
next.m=0;
}
break;
case 6://m->n
if(next.m+next.n>n)
{
next.m=next.m+next.n-n;
next.n=n;
}
else
{
next.n+=next.m;
next.m=0;
}
break;
}
if(check(i,tmp,next))
{
vis[next.s][next.n][next.m]=1;
next.step++;
q.push(next);
}
}
}
return -1;
}
int main()
{
while(cin>>s>>n>>m&&s)
{
if(s&1)
{
cout<<"NO"<<endl;
continue;
}
memset(vis,0,sizeof(vis));
int ans=bfs();
if(ans==-1)
cout<<"NO"<<endl;
else
cout<<ans<<endl;
}
}
hdoj1312 Red and Black
记录下今天的日期:8.30 (最近有些懒散,之前学的东西感觉快忘了emm,赶紧做几道题回忆一下)
题目大意: 有一个矩形瓷砖地,由红黑两种颜色的瓷砖构成,给出一个人的位置,这个人只能走黑色瓷砖,红色瓷砖可以看做是墙,不能过去。问从这个人的位置出发,最多能走多少块瓷砖。(最终结果包括他自己!)
题解: 这应该算是BFS的水题了emm,但是我做的时候还是花费了不少的时间,得赶紧将暑假学的东西拾起来,不然就白学了(手动捂脸)。这题需要注意的一点就是最终结果是包括自己的,也就是说,如果这个人的四周全是红瓷砖(墙),那如果不加特判的话,结果就会是0,而正确结果应该是1,因此在最后要加上特判。
(这题应该也可以用DFS做,如果做出来的话会写在我的另一篇博客里)
AC代码:
#include <iostream>
#include <iomanip>
#include <queue>
#include <string.h>
using namespace std;
char maps[21][21];
int vis[21][21];
int xx,yy,w,h,ans=0;
int dir[4][2]=
{
{0,1},
{0,-1},
{1,0},
{-1,0},
};
struct node
{
int x;
int y;
};
bool check(int x,int y)
{
if(x<0||y<0||x>=h||y>=w||vis[x][y])
return false;
if(maps[x][y]=='#')
return false;
return true;
}
void bfs()
{
queue<node>q;
node start,next;
start.x=xx;
start.y=yy;
q.push(start);
while(!q.empty())
{
node tmp=q.front();
q.pop();
for(int i=0;i<4;i++)
{
next=tmp;
next.x+=dir[i][0];
next.y+=dir[i][1];
if(check(next.x,next.y))
{
ans++;
q.push(next);
vis[next.x][next.y]=1;
}
}
}
}
int main()
{
while(cin>>w>>h&&w+h)
{
ans=0;
memset(maps,0,sizeof(maps));
memset(vis,0,sizeof(vis));
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
cin>>maps[i][j];
if(maps[i][j]=='@')
{
xx=i;
yy=j;
}
}
}
bfs();
if(!ans)//特判,判断是否这个人周围全是红瓷砖
ans=1;
cout<<ans<<endl;
}
}