题目来源:
大致题意:
一个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;
}