Dragon slayer(搜索板题)

题目来源:

2022“杭电杯”中国大学生算法设计超级联赛(1)

Dragon slayer

大致题意:

一个n*m的网格图

人在方块中央 每次从一个方块中央走到另一个方块中央

有k个墙 墙在线上 墙只有水平的和竖直的

人从一个方块到另一个方块时不能越过墙

人每消耗1体力可以完全打破一堵墙 完全打破一堵墙会让这堵墙完全消失

不只是这次越过的部分 而是整个墙都会消失

墙可以重叠 越过重叠的部分时 这部分的每堵墙都需要消耗体力打破

问人从 以(xs,ys)为左下角的方块中央 走到 以(xt,yt)为左下角的方块中央

至少需要消耗多少体力

大致思路:

1.坐标处理

人的坐标在方格中央 (xs+0.5,ys+0.5) 不方便计算 因此将整个坐标系*2

图 n * m → 2*n * 2*m

人 (xs+0.5,ys+0.5) → (2*xs+1,2*ys+1)

墙 (x1,y1)-(x2,y2) → (2*x1,2*y1)-(2*x2,2*y2)

2.DFS枚举所有情况 从中找出可行解中的最优解

k个墙 每个墙有打破/没打破2种情况 一共2^k种情况

其中部分情况 人无法从起点到达终点 不考虑

还有部分情况 人可以从起点到达终点 从这些情况中找出最优解

3.BFS检测每种情况能否从起点到达终点

在DFS时提前在图中处理好墙 之后朴实无华的BFS

复杂度:t * 2^k * n*m

t<=10        k,n,m<=15        总复杂度<=73728000<8e7

AC代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (ll i = l; i <= r; ++i)
#define ROF(i, r, l) for (ll i = r; i >= l; --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
// const db PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const long long LNF = 0x3f3f3f3f3f3f3f3f;
const db EPS = 1.0e-9;
const ll MOD = 1e9 + 7;
const ll MXN = 55;
ll n, m, k;
ll xs, ys, xt, yt;
struct wnd
{
	ll x1, y1, x2, y2;
};
wnd wall[MXN];
ll mp[MXN][MXN];
bool vis[MXN][MXN];
queue<pll> q;
ll dx[5] = {0, 0, 0, -1, 1};
ll dy[5] = {0, 1, -1, 0, 0};
ll ans;

void Modify(ll i, ll v)
{
	ll ldx = min(wall[i].x1, wall[i].x2);
	ll ldy = min(wall[i].y1, wall[i].y2);
	ll rux = max(wall[i].x1, wall[i].x2);
	ll ruy = max(wall[i].y1, wall[i].y2);
	FOR(i, ldx, rux)
	FOR(j, ldy, ruy)
	mp[i][j] += v;
	return;
}
void BFS(ll cost)
{
	memset(vis, false, sizeof(vis));
	while (!q.empty())
		q.pop();
	pll u, v, md;
	u.fir = xs;
	u.sec = ys;
	vis[u.fir][u.sec] = true;
	q.push(u);
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		FOR(i, 1, 4)
		{
			v.fir = u.fir + 2 * dx[i];
			v.sec = u.sec + 2 * dy[i];
			md.fir = u.fir + dx[i];
			md.sec = u.sec + dy[i];
			if (0 <= v.fir && v.fir <= n &&
				0 <= v.sec && v.sec <= m &&
				vis[v.fir][v.sec] == false &&
				mp[md.fir][md.sec] == 0)
			{
				vis[v.fir][v.sec] = true;
				q.push(v);
			}
		}
	}
	if (vis[xt][yt] == true)
		ans = cost;
	return;
}
void DFS(ll i, ll sum)
{
	if (sum >= ans)
		return;
	if (i == k)
	{
		BFS(sum);
		return;
	}
	Modify(i + 1, 1);
	DFS(i + 1, sum);
	Modify(i + 1, -1);
	DFS(i + 1, sum + 1);
	return;
}
void Solve(void)
{
	memset(mp, 0, sizeof(mp));
	ans = LNF;
	cin >> n >> m >> k;
	n *= 2;
	m *= 2;
	cin >> xs >> ys >> xt >> yt;
	xs = 2 * xs + 1;
	ys = 2 * ys + 1;
	xt = 2 * xt + 1;
	yt = 2 * yt + 1;
	FOR(i, 1, k)
	{
		cin >> wall[i].x1 >> wall[i].y1 >> wall[i].x2 >> wall[i].y2;
		wall[i].x1 *= 2;
		wall[i].y1 *= 2;
		wall[i].x2 *= 2;
		wall[i].y2 *= 2;
	}
	DFS(0, 0);
	cout << ans << edl;
	return;
}
int main(void)
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	// #ifdef cincoutcmd
	// freopen("cin.txt","r",stdin);
	// freopen("cout.txt","w",stdout);
	// #endif
	ll t;
	cin >> t;
	while (t--)
		Solve();
	return 0;
}

状态压缩代替DFS:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (ll i = l; i <= r; ++i)
#define ROF(i, r, l) for (ll i = r; i >= l; --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
// const db PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const long long LNF = 0x3f3f3f3f3f3f3f3f;
const db EPS = 1.0e-9;
const ll MOD = 1e9 + 7;
const ll MXN = 55;
ll n, m, k;
ll xs, ys, xt, yt;
struct wnd
{
	ll x1, y1, x2, y2;
};
wnd wall[MXN];
ll mp[MXN][MXN];
bool vis[MXN][MXN];
queue<pll> q;
ll dx[5] = {0, 0, 0, -1, 1};
ll dy[5] = {0, 1, -1, 0, 0};
ll ans;

inline ll Lowbit(ll x)
{
	return x & (-x);
}
void Modify(ll i, ll v)
{
	ll ldx = min(wall[i].x1, wall[i].x2);
	ll ldy = min(wall[i].y1, wall[i].y2);
	ll rux = max(wall[i].x1, wall[i].x2);
	ll ruy = max(wall[i].y1, wall[i].y2);
	FOR(i, ldx, rux)
	FOR(j, ldy, ruy)
	mp[i][j] += v;
	return;
}
void BFS(ll cost)
{
	memset(vis, false, sizeof(vis));
	while (!q.empty())
		q.pop();
	pll u, v, md;
	u.fir = xs;
	u.sec = ys;
	vis[u.fir][u.sec] = true;
	q.push(u);
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		FOR(i, 1, 4)
		{
			v.fir = u.fir + 2 * dx[i];
			v.sec = u.sec + 2 * dy[i];
			md.fir = u.fir + dx[i];
			md.sec = u.sec + dy[i];
			if (0 <= v.fir && v.fir <= n &&
				0 <= v.sec && v.sec <= m &&
				vis[v.fir][v.sec] == false &&
				mp[md.fir][md.sec] == 0)
			{
				vis[v.fir][v.sec] = true;
				q.push(v);
			}
		}
	}
	if (vis[xt][yt])
		ans = cost;
	return;
}
void Solve(void)
{
	memset(mp, 0, sizeof(mp));
	ans = LNF;
	cin >> n >> m >> k;
	n *= 2;
	m *= 2;
	cin >> xs >> ys >> xt >> yt;
	xs = 2 * xs + 1;
	ys = 2 * ys + 1;
	xt = 2 * xt + 1;
	yt = 2 * yt + 1;
	FOR(i, 1, k)
	{
		cin >> wall[i].x1 >> wall[i].y1 >> wall[i].x2 >> wall[i].y2;
		wall[i].x1 *= 2;
		wall[i].y1 *= 2;
		wall[i].x2 *= 2;
		wall[i].y2 *= 2;
	}
	ll lim = (1 << k) - 1;
	FOR(i, 0, lim)
	{
		ll sum = k;
		for (ll j = i; j > 0; j -= Lowbit(j))
			--sum;
		if (sum >= ans)
			continue;
		FOR(j, 1, k)
		if ((i >> (j - 1)) & 1)
			Modify(j, 1);
		BFS(sum);
		FOR(j, 1, k)
		if ((i >> (j - 1)) & 1)
			Modify(j, -1);
	}
	cout << ans << edl;
	return;
}
int main(void)
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	// #ifdef cincoutcmd
	// freopen("cin.txt","r",stdin);
	// freopen("cout.txt","w",stdout);
	// #endif
	ll t;
	cin >> t;
	while (t--)
		Solve();
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Once upon a time, there was a small village nestled in the rolling hills of a verdant forest. The villagers lived simple lives, tending to their farms and livestock, and enjoying the many fruits of the forest. However, they were plagued by a ferocious dragon that would fly down from the mountains to terrorize the village, burning their homes and stealing their livestock. The villagers were at a loss of what to do. They had tried everything they could think of to drive the dragon away, but nothing had worked. They had even offered the dragon all of their food and treasure, but the dragon just continued to come back, destroying more and more of their village. One day, a brave young man named Jack decided that enough was enough. He set out to slay the dragon, armed with nothing but his courage and his wits. He journeyed to the dragon's lair, high in the mountains, and confronted the beast. The dragon breathed fire and roared, but Jack was not afraid. He knew that the dragon was not truly evil, but was simply confused and angry. So he spoke to the dragon, telling it that he understood why it was angry and that he wanted to help. The dragon was taken aback by Jack's words, and it listened as he explained how the villagers had been suffering because of its attacks. The dragon felt guilty and ashamed, and it knew that it had to make things right. So it agreed to stop attacking the village, and it flew off into the sunset, never to be seen again. The villagers rejoiced at the news of the dragon's departure and they thanked Jack for his bravery. He became known as the Dragon Slayer, and his name was remembered in the village for generations to come. The village lived in peace and prosperity, and the forest grew lush and bountiful once more.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值