poj 几道简单的搜索题(二)
题目:poj 3278
题意:
在[0,100000]上,给定两个整数n和k通过 n+1或n-1 或n*2 这3种操作,使得n==k,输出最少的操作次数分析:
bfs入门题,每个状态记录一下位置和步数,然后bfs就好。
题目:poj 1426
题意:
给一个正整数n,找出n的某个倍数m,m可以用01表示。n<=200,m不超过100位
分析:
看完m的数据范围吓傻了QAQ,可是n才200,然后写了个暴力打表,发现没有超过18位的!
这题的正规解法是bfs。
#include<iostream> #include<cstdio> #include<queue> using namespace std; typedef unsigned long long ull; ull bfs(ull n) { queue<ull>q; q.push(1); while(!q.empty()){ ull t=q.front();q.pop(); if(t%n==0)return t; q.push(t*10); q.push(t*10+1); } return 0;//题目说一定有解,不加居然WA! } int main() { ull n; while(cin>>n&&n){ cout<<bfs(n)<<endl; } return 0; }
题目:poj 3126
题意:
给两个四位的素数s和e,每次可以改变一位数字(只能是四位素数),问从s到e的最短路?
分析:
先打个素数表,来判断四位数是否为素数。然后简单的bfs。每次可以改变1位数,那么就一次改变第一位,第二位,第三位,第四位,然后判断是否入队。
有点麻烦的地方是类型转换。
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<sstream> #include<queue> #include<string> #include<algorithm> using namespace std; #define mp make_pair const int N=10000; typedef pair<int,int>pii; bool prime[N],vis[N]; int s,e; void getPrime() { memset(prime,0,sizeof(prime)); //prime[i]==0是素数 int m=sqrt(N+0.5); for(int i=2;i<=m;i++)if(!prime[i]) for(int j=i*i;j<N;j+=i)prime[j]=1; } int bfs() { memset(vis,0,sizeof(vis)); stringstream ss; string s1,s2; int x1,x2; queue<pii>q; q.push(mp(0,s)); vis[s]=1; while(!q.empty()){ pii t=q.front();q.pop(); int step=t.first, x=t.second; if(x==e)return step; ss.clear(); //要注意clear ss<<x;ss>>s1;s2=s1; for(char i='1';i<='9';i++){ ss.clear(); s2[0]=i;ss<<s2;ss>>x1; if(!vis[x1]&&!prime[x1])q.push(mp(step+1,x1)); vis[x1]=1; } s2=s1; for(char i='0';i<='9';i++){ ss.clear(); s2[1]=i;ss<<s2;ss>>x1; if(!vis[x1]&&!prime[x1])q.push(mp(step+1,x1)); vis[x1]=1; } s2=s1; for(char i='0';i<='9';i++){ ss.clear(); s2[2]=i;ss<<s2;ss>>x1; if(!vis[x1]&&!prime[x1])q.push(mp(step+1,x1)); vis[x1]=1; } s2=s1; for(char i='0';i<='9';i++){ ss.clear(); s2[3]=i;ss<<s2;ss>>x1; if(!vis[x1]&&!prime[x1])q.push(mp(step+1,x1)); vis[x1]=1; } } return -1; } int main() { getPrime(); int T;scanf("%d",&T); while(T--){ scanf("%d%d",&s,&e); int t=bfs(); if(t==-1)printf("Impossible\n"); else printf("%d\n",t); } return 0; }
题目:poj 3414
题意:
给出两个杯子的容量A,B,然后给出六种倒水方式:
1.把A灌满
2.把B灌满
3.把A清空
4.把B清空
5.把A中的水倒入B中,有可以倒满的话,A可剩余一些水,不能倒满,A空
6.把B中的贺岁倒入A中,与5相似
通过以上六种方式(实际上是八种),问是否可以得到一杯体积是C的水?
分析:
简单的bfs最短路问题,只不过打印方案比较麻烦。
可以设一个pre,记录一下前一个状态,一个id,记录得到当前状态的操作。这样bfs可以得到最优解后,往前找pre即可。
#include<cstring> #include<cstdio> #include<stack> using namespace std; const int N=111; bool vis[N][N]; int A,B,C; struct state { int x,y,step,pre,id; }q[N*N]; void print(state over) { printf("%d\n",over.step); stack<int>ans; while(over.step){ //往前找,把最短路保存到栈里,然后一个个打印 ans.push(over.id); over=q[over.pre]; } while(!ans.empty()){ int t=ans.top();ans.pop(); switch(t) { case 1: printf("FILL(1)\n");break; case 2: printf("FILL(2)\n");break; case 3: printf("DROP(1)\n");break; case 4: printf("DROP(2)\n");break; case 5: printf("POUR(1,2)\n");break; case 6: printf("POUR(2,1)\n");break; } } } bool bfs() { memset(vis,0,sizeof(vis)); int head=0,tail=0; q[tail++]=((state){0,0,0,-1,-1}); while(head<tail){ state t=q[head]; int a=t.x,b=t.y,step=t.step; if(a==C||b==C){ print(t); return true; } if(!vis[A][b]){ //FILL(1) vis[A][b]=1; q[tail++]=((state){A,b,step+1,head,1}); } if(!vis[a][B]){ //FILL(2) vis[a][B]=1; q[tail++]=((state){a,B,step+1,head,2}); } if(!vis[0][b]){ //DROP(1) vis[0][b]=1; q[tail++]=(state){0,b,step+1,head,3}; } if(!vis[a][0]){ //DROP(2) vis[a][0]=1; q[tail++]=(state){a,0,step+1,head,4}; } if(b+a>B&&!vis[a-(B-b)][B]){ //POUR(1,2),1杯有剩余 vis[a-B+b][B]=1; q[tail++]=(state){a-B+b,B,step+1,head,5}; } if(b+a<=B&&!vis[0][a+b]){ //POUR(1,2) ,1杯子无剩余 vis[0][a+b]=1; q[tail++]=(state){0,a+b,step+1,head,5}; } if(b+a>A&&!vis[A][b-(A-a)]){ //POUR(2,1),2杯子有剩余 vis[A][b-A+a]=1; q[tail++]=(state){A,b-A+a,step+1,head,6}; } if(b+a<=A&&!vis[a+b][0]){ //POUR(2,1),2杯子无剩余 vis[a+b][0]=1; q[tail++]=(state){a+b,0,step+1,head,6}; } head++; } return false; } int main() { scanf("%d%d%d",&A,&B,&C); if(!bfs())printf("impossible\n"); return 0; }