题目大意
题目描述
给定二维平面第一象限上的 n 个弹幕发射器。第 i 个发射器位于坐标 (xi,yi),并向四个方向之一发射一条射线(激光):
-
di=0:向上发射
-
di=1:向右发射
-
di=2:向下发射
-
di=3:向左发射
射线的照明路径包含发射器本身所在的位置。题目保证任意两个发射器不会同时在对方的照明路径上。
现在可以在平面上放置障碍物(允许放置在发射器所在的坐标上),只要障碍物位于某条射线上,就能阻挡该射线的照射。求最少需要放置多少个障碍物,才能使得所有 n 个发射器的照射路径上都至少包含一个障碍物。
输入格式
第一行包含一个整数 t(1≤t≤100),表示测试用例的数量。
每个测试用例第一行包含一个整数 n(1≤n≤300),表示发射器的数量。
接下来 n 行,每行包含三个整数 xi,yi,di(1≤xi,yi≤109,di∈{0,1,2,3}),表示发射器的坐标与发射方向。
保证所有测试用例中 n 的总和不超过 3000。
输出格式
对于每个测试用例,输出一行一个整数,表示最少需要放置的障碍物数量。
样例输入
1 2 3 4 5 6 7 8 9 10
| 2 6 5 5 0 3 7 1 9 9 2 9 1 3 5 2 0 1 20 3 1 1 1 0
|
样例输出
样例解释
在第一个测试用例中,有 6 个发射器。一种最优方案是放置 3 个障碍物,具体位置如下:
-
在坐标 (5,7) 处放置一个障碍物:该点覆盖了第 1 束(从 (5,5) 向上)、第 2 束(从 (3,7) 向右)以及第 5 束(从 (5,2) 向上)激光。
-
在坐标 (9,1) 处放置一个障碍物:该点覆盖了第 3 束(从 (9,9) 向下)以及第 4 束(从 (9,1) 向左)激光。
-
在坐标 (−2025,20) 处放置一个障碍物:该点覆盖了第 6 束(从 (1,20) 向左)激光。
该方案共使用了 3 个障碍物,且可以证明不存在比 3 更少的放置方案。
思路讲解
一种错误的图论建模方式是把激光当作左边的点,把这个障碍物当成右边的点,但是这样子建图是做不出来这道题目的,因为我们不是要让激光和障碍物一一匹配,这个非常容易就能做到。
P3386 【模板】二分图最大匹配
那么要做这道题目,最重要的就是我们要把障碍物看成连边,左边的点指的是这个方向为上下的点,右边的点指的是这个方向为左右的点。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void Solve() { ll N; cin >> N; vector<X_y_d> xyd_ls(N); for (int i = 0; i < N; ++i) { cin >> xyd_ls[i].x >> xyd_ls[i].y >> xyd_ls[i].d; } xyd_ls = unique_xyd_ls(xyd_ls); auto g = build_graph(xyd_ls); Bi_graph_matcher matcher(g,SZ(xyd_ls)); ll mx_match = matcher.mx_match(); ll ans = (SZ(xyd_ls) - 2 * mx_match) + mx_match; cout << ans << "\n"; }
|
AC代码
AC
https://acm.hdu.edu.cn/contest/view-code?cid=1198&rid=18859
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
|
#include <bits/stdc++.h>
#include <utility> #define all(vec) vec.begin(),vec.end() #define lson(o) (o<<1) #define rson(o) (o<<1|1) #define SZ(a) ((long long) a.size()) #define debug(var) cerr << #var <<" = ["<<var<<"]"<<"\n"; #define debug1d(a) \ cerr << #a << " = ["; \ for (int i = 0; i < (int)(a).size(); i++) \ cerr << (i ? ", " : "") << a[i]; \ cerr << "]\n"; #define debug2d(a) \ cerr << #a << " = [\n"; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " ["; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ cerr << (j ? ", " : "") << a[i][j]; \ cerr << "]\n"; \ } \ cerr << "]\n"; #define cend cerr<<"\n-----------\n" #define fsp(x) fixed<<setprecision(x)
using namespace std;
using ll = long long; using ull = unsigned long long; using DB = double; using i128 = __int128; using CD = complex<double>;
static constexpr ll MAXN = (ll) 1e6 + 10, INF = (1ll << 61) - 1; static constexpr ll mod = 998244353; static constexpr double eps = 1e-8; const double PI = acos(-1.0);
ll lT, testcase;
struct X_y_d { ll x; ll y; ll d; };
struct X_y { ll x; ll y;
bool operator<(const X_y &o) const { if (x != o.x) return x < o.x; return y < o.y; } };
bool is_two_laser_intersect(X_y_d a, X_y_d b) { if ((a.d==0 || a.d==2) && (b.d==1 || b.d==3)) { X_y node = {a.x, b.y}; if (a.d == 0) { if (node.y < a.y) { return false; } } if (a.d == 2) { if (node.y > a.y) { return false; } } if (b.d == 1) { if (node.x < b.x) { return false; } } if (b.d == 3) { if (node.x > b.x) { return false; } } return true; }else { return false; } }
auto unique_xyd_ls_detail(const vector<X_y_d> &xyd_ls, ll offset) { vector<X_y_d> res; res.reserve(SZ(xyd_ls)); map<ll, ll> mp1, mp3; for (auto [x,y,d]: xyd_ls) { if (offset) { swap(x, y); } if (d == 0 + offset) { if (!mp1.contains(x)) { mp1[x] = y; } else { mp1[x] = max(mp1[x], y); } } else if (d == 2 + offset) { if (!mp3.contains(x)) { mp3[x] = y; } else { mp3[x] = min(mp3[x], y); } } } for (auto [x_,y_]: mp1) { auto [x,y] = make_tuple(x_, y_); if (offset) swap(x, y); res.push_back({x, y, 0 + offset}); } for (auto [x_,y_]: mp3) { auto [x,y] = make_tuple(x_, y_); if (offset) swap(x, y); res.push_back({x, y, 2 + offset}); } return res; }
auto unique_xyd_ls(const vector<X_y_d> &xyd_ls) { auto res1 = unique_xyd_ls_detail(xyd_ls, 0); auto res2 = unique_xyd_ls_detail(xyd_ls, 1); res1.insert(res1.end(), res2.begin(), res2.end()); #ifdef LOCAL cerr << "xyd_ls:\n"; for (int i = 0; i < SZ(xyd_ls); ++i) { cerr << xyd_ls[i].x << " " << xyd_ls[i].y << " " << xyd_ls[i].d << "\n"; } #endif return res1; }
auto build_graph(const vector<X_y_d> &xyd_ls) { ll idx = SZ(xyd_ls); map<X_y, ll> mp; vector<vector<ll> > g(SZ(xyd_ls) + 2); for (int i = 0; i < SZ(xyd_ls); ++i) { for (int j = i + 1; j < SZ(xyd_ls); ++j) { if (xyd_ls[i].d == 0 || xyd_ls[i].d == 2) { auto flag = is_two_laser_intersect(xyd_ls[i], xyd_ls[j]); if (!flag) { continue; } g[i].push_back(j); } } } return g; }
struct Bi_graph_matcher { vector<vector<ll> > g; vector<char> vis; vector<ll> match; ll left_cnt;
Bi_graph_matcher(vector<vector<ll> > _g, ll _left_cnt) : g(std::move(_g)), vis(SZ(g) + 2), match(SZ(g) + 2, -1), left_cnt(_left_cnt) { }
bool find(ll u) { for (auto to: g[u]) { if (vis[to]) { continue; } vis[to] = true; if (match[to] == -1 || find(match[to])) { match[to] = u; return true; } } return false; }
ll mx_match() { ll ans = 0; for (int i = 0; i <= left_cnt; ++i) { vis.assign(SZ(g) + 2, 0); if (find(i)) { ++ans; } } return ans; } };
void Solve() { ll N; cin >> N; vector<X_y_d> xyd_ls(N); for (int i = 0; i < N; ++i) { cin >> xyd_ls[i].x >> xyd_ls[i].y >> xyd_ls[i].d; } xyd_ls = unique_xyd_ls(xyd_ls); auto g = build_graph(xyd_ls); Bi_graph_matcher matcher(g,SZ(xyd_ls)); ll mx_match = matcher.mx_match(); ll ans = (SZ(xyd_ls) - 2 * mx_match) + mx_match; cout << ans << "\n"; }
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); #ifdef LOCAL cout.setf(ios::unitbuf); #endif cin >> lT; for (testcase = 1; testcase <= lT; ++testcase) Solve();
return 0; }
|
心路历程(WA,TLE,MLE……)
最好显式忽略这个其他情况:

使用 offset 进行 swap,最后也要 swap 回来。

将哨兵值设置为 -1,可以避免 0-based 造成问题。
