7139 Dragon slayer

题目描述:
Long, long ago, the dragon captured the princess. In order to save the princess, the hero entered the dragon’s lair.

The dragon’s lair is a rectangle area of length n and width m. The lower left corner is (0,0) and the upper right corner is (n,m).

The position of the hero is (xs+0.5,ys+0.5).

The position of the dragon is (xt+0.5,yt+0.5).

There are some horizontal or vertical walls in the area. The hero can move in any direction within the area, but cannot pass through walls, including the ends of walls.

The hero wants to go where the dragon is, but may be blocked by walls.

Fortunately, heroes have access to special abilities, and each use of a special ability can make a wall disappear forever.

Since using special abilities requires a lot of physical strength, the hero wants to know how many times special abilities need to be used at least on the premise of being able to reach the position of the evil dragon?

Input
The first line contains an integer T(T≤10) —the number of test cases.

The first line of each test case contains 3 integers n,m,K(1≤n,m,K≤15) —length and width of rectangular area, number of walls

The second line of each test case contains 4 integers xs,ys,xt,yt(0≤xs,xt<n,0≤ys,yt<m) — the position of the hero and the dragon.

The next K lines , each line contains 4 integers x1,y1,x2,y2(0≤x1,x2≤n,0≤y1,y2≤m) — indicates the location of the two endpoints of the wall, ensuring that x1=x2 or y1=y2.

Output
For each test case, a line of output contains an integer representing at least the number of times the special ability was required.

Sample Input

2
3 2 2 
0 0 2 1
0 1 3 1
1 0 1 2
3 2 2 
0 0 2 1
2 1 2 2
1 0 1 1

Sample Output

2
0

思路:
最开始想复杂了,以为是最短路用双端队列做的,后来发现穿过一堵墙之后墙会永远消失,这个条件不好用最短路来判断。
下面用爆搜做的。
一个细节,用位运算记录搜索状态。
例如:共有k个条件,可以选择是否使用,那么就有 2 k 2^k 2k个状态。
此时可以用for(int i=0;i<(1<<k);i++)遍历每个状态。
若要检测这个状态中是否有第j个条件,则可以用(j<<1)&&i来检测。j从0开始标号。
本题枚举每种墙的组合,针对某一种墙的组合,从起点开始广搜,若遇到墙,则无法通过。
比较每一种能到达终点的状态所存在的墙的数量,数量最大的状态即为本题的答案状态。
因为其存在的墙数最多,即剩余的墙的数量最多,即去掉的墙的数量最少,那么答案就是总墙数减去此状态下墙的数量。
代码:

#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
typedef pair<int, int>PII;
using namespace std;
const int N = 1e6 + 10;
int dx[4] = { 1,-1,0,0 }, dy[4] = {0,0,-1,1};
struct edge
{
	int x1, y1, x2, y2;
}w[N];
bool st[20][20];
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		int n, m, k;
		cin >> n >> m >> k;
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		
		for (int i = 1; i <= k; i++)
		{
			int a, b, c, d;
			cin >> a >> b >> c >> d;
			w[i] = {a,b,c,d};
		}

		int cnt = 0;
		int res = -1;
		for (int i = 0; i < (1 << k); i++)
		{
			cnt = 0;
			memset(st, false, sizeof st);
			vector<PII>heng[20];
			vector<PII>shu[20];
			for (int j = 0; j < k; j++)
			{
				if ((1 << j) & i)
				{
					cnt++;
					int a = w[j+1].x1;
					int b = w[j+1].y1;
					int c = w[j+1].x2;
					int d = w[j+1].y2;
					if (a == c) // 横边
					{
						heng[a].push_back({min(b, d), max(b, d)});
					}
					if (b == d) // 竖边
					{
						shu[b].push_back({min(a, c), max(a, c)});
					}
				}
			}
			bool flag = false;
			queue<PII>q;
			q.push({x1,y1});
			st[x1][y1] = true;
			while (!q.empty())
			{
				PII pos = q.front();
				q.pop();
				if (pos.first == x2 && pos.second == y2)
				{
					flag = true;
					break;
				}
				for (int i = 0; i < 4; i++)
				{
					int a = pos.first + dx[i];
					int b = pos.second + dy[i];
					if (a < 0 || a >= n || b < 0 || b >= m)
					{
						continue;
					}
					if (st[a][b])
					{
						continue;
					}
					bool qiang = false; // 是否有墙
					if (a == pos.first) // 横着走
					{
						int yy = max(b, pos.second);
						if (!shu[yy].empty())
						{
							for (auto p : shu[yy])
							{
								int l = p.first;
								int r = p.second;
								if (l <= a && r > a)
								{
									qiang = true;
									break;
								}
							}
						}
					}

					if (b == pos.second) // 竖着走
					{
						int xx = max(a, pos.first);
						if (!heng[xx].empty())
						{
							for (auto p : heng[xx])
							{
								int l = p.first;
								int r = p.second;
								if (l <= b && b < r)
								{
									qiang = true;
									break;
								}
							}
						}
					}

					if (qiang)
					{
						continue;
					}

					q.push({a,b});
					st[a][b] = true;
				}
			}
			if (flag)
			{
				res = max(res, cnt);
			}
		}
		if (res == -1) cout << -1 << endl;
		else cout << k - res << endl;   //结果
		
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值