[NOIP2013]华容道

关于华容道:

算法一:bfs暴搜

      用空格坐标和目标格子坐标作为图的代表用bool数组判重(高性价比)

 得分:60

算法二:最短路

      省去每遍bfs重复搜索的部分 方法:记录某格子在方格位于其k方向时向方向h移动一步所需步数(用bfs求出空格从k方向移动到h的反方向所需的步数) 记录在一个四位数组Go中; (注意 因为bfs将空格直接调整到目标格子当前的的反方向 在调整过程中都不能移动目标格子 所以在bfs之前将目标格子位置的状态设置为不可用)

      定义一个状态:某方格的k方向为空格 用全局变量V对每一个状态编号 对于该方格 若其能移动到h方向则把两个状态加边(注意两个状态中的空格方向的处理)

      对于每一个读入的初始点 定义一个新的状态编号S(因为目标格子周围不一定有空格 不能用已编好的编号进行对映) 用bfs求出将空格子移动到目标格子上下左右四个方向所需要的步数 并将S与其连边 

      同理 对于每一个目标点 定义一个新的状态编号T  将其与周围四个格子连边(连边时周围格子的空格方位是目标格子)

      用SPFA求出由ST的最短路径即可;

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define MAXN 30
#define MAXP 100000
#define INF (1 << 25)
using namespace std;
struct Node{
	int v, wt;
	Node *next;
}Edge[MAXP*2+10];
Node *adj[MAXP+10];
Node *ecnt = &Edge[0];
struct node{
	int x, y;
};
int cx[] = {-1, 1, 0, 0};
int cy[] = {0, 0, -1, 1};
int sx, sy, ex, ey, tx, ty;
int n, m, ma[MAXN+10][MAXN+10], A[MAXN+10][MAXN+10][5], q, d[MAXN+10][MAXN+10], dis[MAXP+10], Go[MAXN+10][MAXN+10][5][5], V, S, T;
bool vis[MAXP+10];
void addedge(int u, int v, int wt)
{
	Node *p = ++ecnt;
	p->v = v;
	p->wt = wt;
	p->next = adj[u];
	adj[u] = p;
}

int bfs(int sx, int sy, int tx, int ty)
{
	if(sx == tx && sy == ty)
		return 0;
	queue <node> q;
	while(!q.empty())
		q.pop();
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			d[i][j] = INF;
	d[sx][sy] = 0;
	node a;
	a.x = sx;
	a.y = sy;
	q.push(a);
	while(!q.empty())
	{
		a = q.front();q.pop();
		int x = a.x;
		int y = a.y;
		for(int i = 0; i < 4; i++)
		{
			int xx = x + cx[i];
			int yy = y + cy[i];
			if(ma[xx][yy] && d[xx][yy] == INF)
			{
				d[xx][yy] = d[x][y] + 1;
				if(xx == tx && yy == ty)
					return d[x][y]+1;
				a.x = xx;
				a.y = yy;
				q.push(a);
			}
		}
	}
	return INF;
}
struct cmp{
	bool operator()(int a, int b)
	{
		return dis[a] > dis[b];
	}
};
/*priority_queue <int, vector<int>, cmp> Q;
int SPFA()
{
	for(int i = 1; i <= V; i++)
		dis[i] = INF;                         // slower
	while(!Q.empty())
		Q.pop();
	dis[S] = 0;
	memset(vis, true, sizeof(vis));
	Q.push(S);
	while(!Q.empty())
	{
		int u = Q.top();
		Q.pop();
		if(!vis[u])
			continue;
		vis[u] = false;
		if(u == T)
			return dis[T];
		for(Node *p = adj[u]; p; p = p->next)
		{
			int v = p->v;
			if(dis[v] > dis[u] + p->wt)
			{
				dis[v] = dis[u] + p->wt;
				Q.push(v);
				vis[v] = true;
			}
		}
	}
	return dis[T] < INF ? dis[T] : -1;
}*/
queue <int> Q;
int SPFA()
{
	for(int i = 1; i <= V; i++)           // faster
		dis[i] = INF;
	while(!Q.empty())
		Q.pop();
	dis[S] = 0;
	memset(vis, 0, sizeof(vis));
	Q.push(S);
	vis[S] = true;
	while(!Q.empty())
	{
		int u = Q.front();
		Q.pop();
		vis[u] = false;
		for(Node *p = adj[u]; p; p = p->next)
		{
			int v = p->v;
			if(dis[v] > dis[u] + p->wt)
			{
				dis[v] = dis[u] + p->wt;
				if(!vis[v])
				{
					Q.push(v);
					vis[v] = true;
				}
			}
		}
	}
	return dis[T] < INF ? dis[T] : -1;
}
void init()
{
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			for(int k = 0;k < 4; k++)
				for(int h = 0; h < 4; h++)
					Go[i][j][k][h] = INF;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			if(ma[i][j])
			{
				ma[i][j] = 0;
				for(int k = 0; k < 4; k++)
					if(ma[i+cx[k]][j+cy[k]])
					{
						for(int h = 0; h < 4; h++)
							if(ma[i+cx[h]][j+cy[h]])
								Go[i][j][k][h] = bfs(i + cx[k], j + cy[k], i + cx[h], j + cy[h])+1;
					}
				ma[i][j] = 1;
			}
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			for(int k = 0;k < 4; k++)
				for(int h = 0; h < 4; h++)
					if(Go[i][j][k][h] != INF)
						addedge(A[i][j][k], A[i+cx[h]][j+cy[h]][h^1], Go[i][j][k][h]);
}
void solve()
{
	for(int i = 1; i <= q; i++)
	{
		scanf("%d%d%d%d%d%d", &ex, &ey, &sx, &sy, &tx, &ty);
		if(sx == tx && sy == ty)
		{
			printf("0\n");
			continue;
		}
		if((ma[sx][sy] == 0) || (ma[tx][ty] == 0))
		{
			printf("-1\n");
			continue;
		}
		S = ++V;
		T = ++V;
		ma[sx][sy] = 0;
		for(int i = 0; i < 4; i++)
			if(ma[sx+cx[i]][sy+cy[i]])
			{
				int Dis = bfs(ex, ey, sx+cx[i], sy+cy[i]);
				if(Dis != INF)
					addedge(S, A[sx][sy][i], Dis);
			}
		ma[sx][sy] = 1;
		for(int i = 0; i < 4; i++)
			if(ma[tx+cx[i]][ty+cy[i]])
				addedge(A[tx][ty][i], T, 0);
		printf("%d\n", SPFA());
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
		{
			scanf("%d", &ma[i][j]);
			for(int k = 0; k < 4; k++)
				A[i][j][k] = ++V;
		}
	init();
	solve();
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
noip2013普及组初赛是全国信息学奥林匹克联赛的一场选拔赛。该比赛旨在选拔初学者,对编程和算法有一定基础的学生,通过比赛形式来考察他们的知识水平和解题能力。 比赛题目通常会涉及各个领域的算法和数据结构,如图论、动态规划、数论等。题目难度逐步增加,从简单的输出结果,到复杂的程序设计与代码实现,考察选手的逻辑思维和编程能力。 参赛选手需要通过自己的思考和编程实现来解决题目,同时时间也是一个重要因素。比赛中,选手需要在规定的时间内独立完成所有题目,对于复杂的题目需要迅速想出解题思路并进行编码。因此,在比赛中,选手的临场发挥和解题速度也是需要考虑的因素。 noip2013普及组初赛的结果将作为选拔阶段的一个重要依据,选出表现出色的选手进入到更高阶段的比赛,对于他们来说,这是一次展示自己实力的机会。 此外,noip2013普及组初赛,也给了参赛选手一个交流的平台。选手们可以通过比赛结交同好,相互切磋,共同进步。同时,比赛结束后,还有详细的解题分析和讲解,有助于参赛选手对自己在比赛中的不足进行反思与改进。 总之,noip2013普及组初赛是一个考察学生编程和算法能力的选拔赛,通过比赛的形式来选拔出优秀的选手。这对于参赛选手来说,是一次展示自己才华的机会,也是一个展示自己实力和提高自己能力的平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值