• 搜索训练笔记


    BFS(广度优先搜索)

    Catch The Cow

    • 题目大意

    在一坐标轴上给定起点和终点,每次行动可以向左、向右或将目前的坐标变为两倍,问走到终点的最少步数。

    $ n \leq 100000 , k \leq 100000$

    • 思路
      注意到题目中的“最少”,考虑使用bfs来处理即可。
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    struct node {
    	int pos;
    	int time;
    };
    int vis[100010];
    int n,m;
    int bfs(int pos) {
    	queue <node> q;
    	node a;
    	a.pos = pos;
    	a.time = 0;
    	q.push(a);
    	node nxt;
    	while(!q.empty()) {
    		node u = q.front();
    		q.pop();
    		if(u.pos == m) {
    			return u.time;
    		}
    		nxt = u;
    		nxt.pos = u.pos + 1;
    		if(!(nxt.pos < 0 or nxt.pos > 100000 or vis[nxt.pos])) {
    			nxt.time = u.time + 1;
    			vis[nxt.pos] = 1;
    			q.push(nxt);
    		}
    		nxt.pos = u.pos - 1;
    		if(!(nxt.pos < 0 or nxt.pos > 100000 or vis[nxt.pos])) {
    			nxt.time = u.time + 1;
    			vis[nxt.pos] = 1;
    			q.push(nxt);
    		}
    		nxt.pos = u.pos << 1;
    		if(!(nxt.pos < 0 or nxt.pos > 100000 or vis[nxt.pos])) {
    			nxt.time = u.time + 1;
    			vis[nxt.pos] = 1;
    			q.push(nxt);
    		}
    	}
    }
    
    int main () {
    	cin >> n >> m;
    	cout << bfs(n) << endl;
    	return 0;
    }
    

    Find The Multiple

    • 题目大意

    找一个数m的非零倍数,这个非零倍数只由0,1组成,\(m \leq 200\)

    • 思路
      注意到直接搜的话,容易TLE,直接打表(
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define int long long
    int lis[] = {0,1,10,111,100,10,1110,1001,1000,111111111,10,11,11100,1001,10010,1110,10000,11101,1111111110,11001,100,10101,110,110101,111000,100,10010,1101111111,100100,1101101,1110,111011,100000,111111,111010,10010,11111111100,111,110010,10101,1000,11111,101010,1101101,1100,1111111110,1101010,10011,1110000,1100001,100,100011,100100,100011,11011111110,110,1001000,11001,11011010,11011111,11100,100101,1110110,1111011111,1000000,10010,1111110,1101011,1110100,10000101,10010,10011,111111111000,10001,1110,11100,1100100,1001,101010,10010011,10000,1111111101,111110,101011,1010100,111010,11011010,11010111,11000,11010101,1111111110,1001,11010100,10000011,100110,110010,11100000,11100001,11000010,111111111111111111,100,101,1000110,11100001,1001000,101010,1000110,100010011,110111111100,1001010111,110,111,10010000,1011011,110010,1101010,110110100,10101111111,110111110,100111011,111000,11011,1001010,10001100111,11101100,1000,11110111110,11010011,10000000,100100001,10010,101001,11111100,11101111,11010110,11011111110,11101000,10001,100001010,110110101,100100,10011,100110,1001,1111111110000,11011010,100010,1100001,11100,110111,11100,1110001,11001000,10111110111,10010,1110110,1010100,10101101011,100100110,100011,100000,11101111,11111111010,1010111,1111100,1111110,1010110,11111011,10101000,10111101,111010,1111011111,110110100,1011001101,110101110,100100,110000,100101111,110101010,11010111,11111111100,1001111,10010,100101,110101000,1110,100000110,1001011,1001100,1010111010111,110010,11101111,111000000,11001,111000010,101010,110000100,1101000101,1111111111111111110,111000011,1000};
    //int bfs(int now) {
    //	queue <int> q;
    //	q.push(1);
    //	while(!q.empty()) {
    //		int u = q.front();
    //		q.pop();
    //		if(u % now == 0) {
    //			return u;
    //		}
    //		q.push(u * 10);
    //		q.push(u * 10 + 1);
    //	}
    //}
    int m;
    signed main () {
    	//freopen("s.txt","w",stdout);
    	while(~scanf("%lld",&m) and m) {
    		cout << lis[m] << endl;
    	}
    	return 0;
    }
    

    Prime Path

    • 题目大意

    给两个素数,问能否通过变化每一位上的数字,使得较小的素数变为较大的,并且变化过程所拓展的数也应是素数,多组数据

    • 思路
      每一次改变每一位的数值,从个十百千递增修改,保证严格递增修改,之后bfs即可。
      ps:不知道为什么我在poj上提交的时候会有sqrt重定义错误的问题,改为g++就没问题了。。。
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    struct node {
    	int num;
    	int stp;
    };
    int n;
    int vis[10010];
    bool isprime(int n) {
    	if(n == 0 or n == 1) return 0;
    	else if(n == 2 or n == 3) return 1;
    	else {
    		for(int i = 2;i <= int(sqrt(n)); ++i) {
    			if(n % i == 0) return 0;
    		}
    		return 1;
    	}
    }
    int bfs(int st,int ed) {
    	if(st == ed) return 0;
    	memset(vis,0,sizeof vis);
    	queue <node> q;
    	node tmp;
    	tmp.num = st;
    	tmp.stp = 0;
    	q.push(tmp);
    	vis[tmp.num] = 1;
    	while(!q.empty()) {
    		node u = q.front();
    		q.pop();
    		for(int i = 1;i <= 9; i += 2) {
    			int now = u.num / 10 * 10 + i;
    			if(now == ed) {
    				return u.stp + 1;
    			}
    			if(!vis[now] and isprime(now)) {
    				vis[now] = 1;
    				node ss;
    				ss.num = now;
    				ss.stp = u.stp + 1;
    				q.push(ss);
    			}
    		}
    		for(int i = 0;i <= 9; ++i) {
    			int now = u.num / 100 * 100 + i * 10 + u.num % 10;
    			if(now == ed) {
    				return u.stp + 1;
    			}
    			if(!vis[now] and isprime(now)) {
    				vis[now] = 1;
    				node ss;
    				ss.num = now;
    				ss.stp = u.stp + 1;
    				q.push(ss);
    			}
    		}
    		for(int i = 0;i <= 9; ++i) {
    			int now = u.num / 1000 * 1000 + i * 100 + u.num % 100;
    			if(now == ed) {
    				return u.stp + 1;
    			}
    			if(!vis[now] and isprime(now)) {
    				vis[now] = 1;
    				node ss;
    				ss.num = now;
    				ss.stp = u.stp + 1;
    				q.push(ss);
    			}
    		}
    		for(int i = 1;i <= 9; ++i) {
    			int now = i * 1000 + u.num % 1000;
    			if(now == ed) {
    				return u.stp + 1;
    			}
    			if(!vis[now] and isprime(now)) {
    				vis[now] = 1;
    				node ss;
    				ss.num = now;
    				ss.stp = u.stp + 1;
    				q.push(ss);
    			}
    		}
    	}
    	return -1;
    }
    int main () {
    	cin >> n;
    	for(int i = 1;i <= n; ++i) {
    		int x,y;
    		cin >> x >> y;
    		int tmp = bfs(x,y);
    		if(tmp == -1) {
    			puts("Impossible");
    		}
    		else {
    			cout << tmp << endl;
    		}
    	}
    	return 0;
    }
    

    Pots

    • 题目大意

    给两个有容积的盆,和一个需要凑出来的水升数,你只能加满水,倒水,或将一个盆中水导入另外一个,至少经过几步能完成,并输出路径

    • 思路
      \(vis_{i,j}\)表示左右盆中水盛情况是否达到过,每次模拟一个操作,记录并搜索即可,代码后补
  • 相关阅读:
    mongodb进阶三之mongodb管理
    《Javascript权威指南》学习笔记之十九--HTML5 DOM新标准---处理文档元信息和管理交互能力
    TCP/IP协议族-----21、文件传送:FTP和TFTP
    Leetcode Two Sum
    MongoDB 操作手冊CRUD 删除 remove
    VSync Count 垂直同步
    机器学习实战笔记1(机器学习基础)
    Cacti监控MySQL实现过程中碰到的问题解汇总
    【LeetCode】- Search Insert Position(查找插入的位置)
    去除百度推广的广告
  • 原文地址:https://www.cnblogs.com/akoasm/p/14635300.html
Copyright © 2020-2023  润新知