小白要跟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;
}
}