zoukankan      html  css  js  c++  java
  • 【LOJ3099】[SNOI2019]积木(搜索)

    lca 学长出的我省省选的神仙题目 省强我菜系列

    题目

    LOJ3399

    分析

    我可能说不清楚,对着代码理解吧 …… 感觉这题的主要难点是:不要想他具体是怎么操作的,只要知道他一定存在一种操作方式能够实现就行了。

    首先要注意到一个很重要的性质:对于当前空格所在的点,除非这个点在目标中就是空格,否则一定可以通过一步操作使这个点变得和目标中一样(下称「变得和目标中一样」为「归位」)。例如,如果这个点最终是朝上的(意思是这个点是一个上下方向的块的下半部分,朝下、朝左、朝右同理),那么无论它上面是一个朝上还是朝左还是朝右(显然不可能朝下)的块,都可以通过移动它上面的块来使这个点变得朝上。这样只需要不断地通过这种操作使空格所在的块归位,就可以让空格到达目标中的空格的位置。

    但是,这个过程中不能保证访问到了所有格子,所以有些未归位的格子可能没有被发现。因此在把空格归位后要去主动寻找未归位的格子。具体方法是用 dfs 主动寻找未归位的格子。虽然这样会让已经归位的格子变成未归位,但是回溯的时候挪回去就行了。每找到一个未归位的格子就像上一段描述的一样使它归位,直到空格又回到 dfs 找到的这个地方。如此把所有格子都 dfs 一遍,就能让所有格子归位。

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    namespace zyt
    {
    	const int N = 2e3 + 10, M = 8e6 + 10, CH = 128;
    	const int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
    	const char opt[] = {'R', 'L', 'D', 'U'}, ch[] = {'<', '>', 'n', 'u'};
    	char a[N][N], b[N][N], ans[M];
    	bool vis[N][N];
    	int cntans, n, m, dir[CH];
    	void move(const int d, int &x, int &y)
    	{
    		ans[cntans++] = opt[d];
    		int x1 = x + dx[d], y1 = y + dy[d];
    		if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= m)
    			fprintf(stderr, "gg");
    		int x2 = x1 + dx[dir[a[x1][y1]]], y2 = y1 + dy[dir[a[x1][y1]]];
    		a[x][y] = ch[d], a[x1][y1] = ch[d ^ 1], a[x2][y2] = 'o';
    		x = x2, y = y2;
    	}
    	void go(int &x, int &y, const int x1, const int y1)
    	{
    		while (x != x1 || y != y1)
    			move(dir[b[x][y]], x, y);
    	}
    	void dfs(int x, int y)
    	{
    		vis[x][y] = true;
    		for (int d = 0; d < 4; d++)
    		{
    			int x1 = x + dx[d], y1 = y + dy[d];
    			if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= m || vis[x1][y1])
    				continue;
    			if (a[x1][y1] != b[x1][y1])
    			{
    				int x0 = x, y0 = y;
    				move(d, x, y);
    				go(x, y, x0, y0);
    			}
    			vis[x1][y1] = true;
    			int dd = dir[a[x1][y1]];
    			move(d, x, y);
    			dfs(x, y);
    			move(dd ^ 1, x, y);
    		}
    	}
    	int work()
    	{
    		dir['<'] = 0, dir['>'] = 1, dir['n'] = 2, dir['u'] = 3;
    		scanf("%d%d", &n, &m);
    		for (int i = 0; i < n; i++)
    			scanf("%s", a[i]);
    		for (int i = 0; i < n; i++)
    			scanf("%s", b[i]);
    		int x, y, x1, y1;
    		for (int i = 0; i < n; i++)
    			for (int j = 0; j < m; j++)
    			{
    				if (a[i][j] == 'o')
    					x = i, y = j;
    				if (b[i][j] == 'o')
    					x1 = i, y1 = j;
    			}
    		go(x, y, x1, y1);
    		dfs(x, y);
    		printf("%s", ans);
    		return 0;
    	}
    }
    int main()
    {
    	return zyt::work();
    }
    
  • 相关阅读:
    java线程安全单例
    ConcurrentHashMap 中putIfAbsent 和put的区别
    Google Guava -缓存cache简单使用
    Jstorm TimeCacheMap源代码分析
    poj 3277...离散化+线段树...
    spoj 1716...动态区间的最大连续子段和问题...点修改...
    spark
    hdu 1754...忘了个getchar(),蛋疼了半天...原来划水也有蛋疼的时候...
    hdu 1556...线段树划水...
    PHP学习笔记06——面向对象版图形计算器
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/12010925.html
Copyright © 2011-2022 走看看