• 关于 BFS


    bfs与优化

    前言:

    这玩意比深搜好多了好吗

    深搜是真的恶心人


    1. 电路维修(打开灯泡)

    思路:

    根据题意建立边权为 0 或 1 的无向图

    双端队列 bfs

    code:

    /*
      Time: 12.27
      Worker: Blank_space
      Source: #2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<queue>
    #include<iostream>
    using namespace std;
    /*--------------------------------------头文件*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const int FFF = 0x8fffffff;
    /*------------------------------------常量定义*/
    int n, m, dis[C];
    struct edge{
    	int v ,w, nxt;
    }e[C];
    int head[C], js;
    bool vis[C];
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    void add_edge(int u, int v, int w)
    {
    	e[++js].v = v; 
    	e[js].w = w;
    	e[js].nxt = head[u];
    	head[u] = js;
    }
    /*----------------------------------------函数*/
    int main()
    {
        n = read(); m = read();
        for(int i = 1; i <= n; i++)
        	for(int j = 1; j <= m; j++)
        	{
        		char s; bool p = 0;	cin >> s;
        		if(s == '/') p = 1;
        		add_edge((i - 1) * (m + 1) + j, i * (m + 1) + j + 1, p);
        		add_edge(i * (m + 1) + j + 1, (i - 1) * (m + 1) + j, p);
        		add_edge((i - 1) * (m + 1) + j + 1, i * (m + 1) + j, p ^ 1);
        		add_edge(i * (m + 1) + j, (i - 1) * (m + 1) + j + 1, p ^ 1);
        	}
        for(int i = 1; i <= n * m + n + m + 1; i++) dis[i] = INF;
    	deque <int> q;
        q.push_back(1); dis[1] = 0;// vis[1] = 1;
        while(!q.empty())
        {
        	int u = q.front();
        	q.pop_front();
        	if(vis[u]) continue;
        	vis[u] = 1;
        	for(int i = head[u]; i; i = e[i].nxt)
        	{
        		int v = e[i].v, w = e[i].w;
        		dis[v] = min(dis[v], dis[u] + w);
        		if(w) q.push_back(v);
        		else q.push_front(v);
        	}
        }
        if(dis[(m + 1) * (n + 1)] == INF) puts("NO SOLUTION");
        else printf("%d", dis[(m + 1) * (n + 1)]);
    	return 0;
    }
    

    2. 魔板

    思路:

    看到书上是康托展开

    但是这个题是按照自己的思路写的

    有一点dp的思想

    先把当前的状态写成八个整数的形式

    由每一种方式作为一种状态

    map映射

    通过三种操作搜索能够转移的状态

    每一种状态第一次被搜到的时候就是达到这一状态的最小次数 通过这一点记录路径

    code:

    /*
      Time: 12.27
      Worker: Blank_space
      Source: #10027. 「一本通 1.4 例 2」魔板
      以每种情况作为一种状态 map映射
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<string>
    using namespace std;
    /*--------------------------------------头文件*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int E = 12345678;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const int FFF = 0x8fffffff;
    /*------------------------------------常量定义*/
    int a[10];
    map <int, int> dis;
    map <int, string> path;
    queue <int> q;
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    int g()
    {
    	int sum = 0;
    	for(int i = 1; i <= 8; i++) sum = sum * 10 + a[i];
    	return sum;
    }
    void change(int opt)
    {
    	if(opt == 1)
    		for(int i = 1; i <= 4; i++) swap(a[i], a[9 - i]);
    	if(opt == 2)
    	{
    		int x = a[4], y = a[5];
    		for(int i = 3; i >= 1; i--) a[i + 1] = a[i];
    		for(int i = 5; i <= 7; i++) a[i] = a[i + 1];
    		a[1] = x; a[8] = y;
    	}
    	if(opt == 3)
    	{
    		int x = a[7];
    		a[7] = a[6];
    		a[6] = a[3];
    		a[3] = a[2];
    		a[2] = x;
    	}
    	if(opt == 4)
    	{
    		int x = a[1], y = a[8];
    		for(int i = 1; i <= 3; i++) a[i] = a[i + 1];
    		for(int i = 7; i >= 5; i--) a[i + 1] = a[i];
    		a[4] = x; a[5] = y;
    	}
    	if(opt == 5)
    	{
    		int x = a[7];
    		a[7] = a[2];
    		a[2] = a[3];
    		a[3] = a[6];
    		a[6] = x;
    	}
    }
    void cover(int x)
    {
    	for(int i = 8; i >= 1; i--)
    	{
    		a[i] = x % 10;
    		x /= 10;
    	}
    }
    /*----------------------------------------函数*/
    int main()
    {
        for(int i = 1; i <= 8; i++) a[i] = read();
        int n = g();
        q.push(E);
        while(!q.empty())
        {
        	int u = q.front();
        	q.pop();
        	if(u == n) break;
        	cover(u);
        	for(int i = 1; i <= 3; i++)
        	{
        		change(i);
        		int v = g();
        		if(!dis.count(v))
        		{
        			dis[v] = dis[u] + 1;
        			q.push(v);
        			string s1 = path[u];
        			if(i == 1) s1 += 'A';
        			if(i == 2) s1 += 'B';
        			if(i == 3) s1 += 'C';
        			path[v] = s1;
        		}
        		change(i != 1 ? i + 2 : 1);
        	}
        }
        printf("%d
    ", dis[n]);
        cout << path[n];
    	return 0;
    }
    

    3. Knight Moves

    思路:

    双向bfs

    如果其中一个搜索到了另一个搜到过的状态 则搜索完成 对状态进行拼接

    code:

    /*
      Time: 12.27
      Worker: Blank_space
      Source: #10028. 「一本通 1.4 例 3」Knight Moves
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<queue>
    #include<string.h>
    #define emm(x) memset(x, 0, sizeof x)
    using namespace std; 
    /*--------------------------------------头文件*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const int FFF = 0x8fffffff;
    /*------------------------------------常量定义*/
    int T, m, sx, sy, tx, ty;
    int dx[9] = {0, 1, 1, -1, -1, 2, 2, -2, -2};
    int dy[9] = {0, 2, -2, 2, -2, 1, -1, 1, -1};
    struct node {
    	int x, y;
    };
    queue <node> q1;
    queue <node> q2;
    int vis1[310][310], vis2[310][310];
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    void clear1()
    {
    	queue <node> q;
    	swap(q, q1);
    }
    void clear2()
    {
    	queue <node> q;
    	swap(q, q2);
    }
    void work()
    {
    	emm(vis1); emm(vis2); clear1(); clear2();
    	m = read(); sx = read(); sy = read(); tx = read(); ty = read();
    	if(sx == tx && sy == ty) {puts("0"); return ;}
    	q1.push((node){sx, sy}); q2.push((node){tx, ty});
    	while(!q1.empty() && !q2.empty())
    	{
    		if(q1.size() <= q2.size() || q2.empty())
    		{
    			node t = q1.front(); q1.pop();
    			int x = t.x, y = t.y;
    			for(int i = 1; i <= 8; i++)
    			{
    				int xx = x + dx[i], yy = y + dy[i];
    				if(xx < 0 || xx > m || yy < 0 || yy > m || vis1[xx][yy]) continue;
    				vis1[xx][yy] = vis1[x][y] + 1;
    				if(vis2[xx][yy]) {printf("%d
    ", vis1[xx][yy] + vis2[xx][yy]); return ;}
    				q1.push((node){xx, yy});
    			}
    			continue;
    		}
    		if(q1.size() >  q2.size() || q1.empty())
    		{
    			node t = q2.front(); q2.pop();
    			int x = t.x, y = t.y;
    			for(int i = 1; i <= 8; i++)
    			{
    				int xx = x + dx[i], yy = y + dy[i];
    				if(xx < 0 || xx > m || yy < 0 || yy > m || vis2[xx][yy]) continue;
    				vis2[xx][yy] = vis2[x][y] + 1;
    				if(vis1[xx][yy]) {printf("%d
    ", vis1[xx][yy] + vis2[xx][yy]); return ;}
    				q2.push((node){xx, yy});
    			}
    			continue;
    		}
    	}
    }
    /*----------------------------------------函数*/
    int main()
    {
        T = read();
        while(T--) work();
    	return 0;
    }
    

    4. 棋盘游戏

    思路:

    看到题的第一想法是状压

    感觉确实能做

    但是状态的转移情况有点多 不是很会转移

    于是推一下 看有没有别的方法

    感觉这个题可以看做直接将不同的棋子移到最近的不同的位置

    试一下

    80 Pts

    这样做是可以的 但是有一点bug:

    一个棋子先搜到一个自己位置可能会占用其他棋子的最优位置 导致答案不是最优

    手动改变一下搜索顺序 从外圈开始搜

    100 Pts

    /*
      Time: 12.27
      Worker: Blank_space
      Source: #10029. 「一本通 1.4 练习 1」棋盘游戏
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cmath>
    using namespace std;
    /*--------------------------------------头文件*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const int FFF = 0x8fffffff;
    /*------------------------------------常量定义*/
    int mp1[5][5], mp2[5][5], ans;
    struct node {
    	int x, y;
    };
    int dx[5] = {0, 1, -1, 0, 0};
    int dy[5] = {0, 0, 0, 1, -1};
    bool vis[5][5];
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    void bfs(int x, int y)
    {
    	queue <node> q;
    	q.push((node){x, y});
    	while(!q.empty())
    	{
    		node h = q.front(); q.pop();
    		int _x = h.x, _y = h.y;
    		for(int i = 1; i <= 4; i++)
    		{
    			int xx = _x + dx[i], yy = _y + dy[i];
    			if(xx < 1 || xx > 4 || yy < 1 || yy > 4) continue;
    			if(!vis[xx][yy] && mp2[xx][yy])
    			{
    				ans += abs(xx - x) + abs(yy - y);
    				vis[xx][yy] = 1; return ;
    			}
    			q.push((node){xx, yy});
    		}
    	}
    }
    /*----------------------------------------函数*/
    int main()
    {
        for(int i = 1; i <= 4; i++)
        	for(int j = 1; j <= 4; j++)
        	{
        		char c; cin >> c;
        		mp1[i][j] = c - 48;
        	}
        for(int i = 1; i <= 4; i++)
        	for(int j = 1; j <= 4; j++)
    		{
    			char c; cin >> c;
    			mp2[i][j] = c - 48;
    			if(mp1[i][j] == mp2[i][j]) vis[i][j] = 1;
    		}
    	for(int i = 1; i <= 4; i++) if(mp1[1][i] > mp2[1][i]) bfs(1, i);
    	for(int i = 1; i <= 4; i++) if(mp1[4][i] > mp2[4][i]) bfs(4, i);
    	for(int i = 1; i <= 4; i++) if(mp1[2][i] > mp2[2][i]) bfs(2, i);
    	for(int i = 1; i <= 4; i++) if(mp1[3][i] > mp2[3][i]) bfs(3, i);
        printf("%d", ans);
    	return 0;
    }
    

    5. Keyboarding

    没做

    6. 山峰和山谷

    思路:

    裸的bfs

    一开始判重出了点问题 83 Pts

    没有发现 尝试加了一个优化 78 Pts

    ???

    弄上判重 100 Pts

    /*
      Time: 12.27
      Worker: Blank_space
      Source: #2653. 「POI2007」山峰和山谷 Ridges and Valleys
    */
    /*--------------------------------------------*/
    #include<cstdio>
    #include<string.h>
    #include<queue>
    using namespace std;
    /*--------------------------------------头文件*/
    const int A = 1e4 + 7;
    const int B = 1e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const int FFF = 0x8fffffff;
    /*------------------------------------常量定义*/
    int n, mp[1010][1010], ans1, ans2;
    bool vis[1010][1010];
    struct node {
    	int x, y;
    };
    int dx[9] = {0, 0, 0, 1, 1, 1, -1, -1, -1};
    int dy[9] = {0, 1, -1, 0, 1, -1, 0, 1, -1};
    /*------------------------------------变量定义*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    /*----------------------------------------快读*/
    void bfs(int x, int y)
    {
    	queue <node> q;
    	q.push((node){x, y});
    	int g1 = 1, d = 0;// 1 周围低于中间  2 高
    	while(!q.empty())
    	{
    		node h = q.front(); q.pop();
    		int _x = h.x, _y = h.y;
    		for(int i = 1; i <= 8; i++)
    		{
    			int xx = _x + dx[i], yy = _y + dy[i];
    			if(xx < 1 || xx > n || yy < 1 || yy > n) continue;
    			if(mp[xx][yy] == mp[_x][_y] && !vis[xx][yy]) q.push((node){xx, yy}), vis[xx][yy] = 1;
    			if(d == 0)
    				d = mp[xx][yy] < mp[_x][_y] ? 1 : mp[xx][yy] > mp[_x][_y] ? 2 : 0;
    			else if(!g1) continue;
    			else if(mp[xx][yy] > mp[_x][_y] && d == 1) g1 = 0;
    			else if(mp[xx][yy] < mp[_x][_y] && d == 2) g1 = 0;
    		}
    	}
    	if(d == 1) ans1 += g1;
    	if(d == 2) ans2 += g1;
    	if(d == 0) ans1 = 1, ans2 = 1;
    }
    /*----------------------------------------函数*/
    int main()
    {
        n = read();
        for(int i = 1; i <= n; i++)
        	for(int j = 1; j <= n; j++) mp[i][j] = read();
        for(int i = 1; i <= n; i++)
        	for(int j = 1; j <= n; j++)
        		if(!vis[i][j])
    				bfs(i, j);
    	printf("%d %d", ans1, ans2);
    	return 0;
    }
    
    
  • 相关阅读:
    RecyclerView的坑
    Edittext默认无焦点
    EditText光标位置
    录音功能暂停的实现思路
    Java clone()方法使用说明
    Android systemserver分析ThrottleService 介绍
    php 输出函数常用类型转换符
    Android BitmapDrawable()的使用
    java equal和==的比较,尤其注意基本类型和基本类型的包装类型的比较
    android HeaderViewListAdapter的介绍
  • 原文地址:https://www.cnblogs.com/blank-space-/p/14198798.html
Copyright © 2020-2023  润新知