Treasure Hunt · znzryb
## 思路讲解
The Doors 的想法,跑dij。
感觉可以套用这个做法,把距离都变成1,就是要开多少门。
## AC代码
[https://vjudge.net/solution/63304444](https://vjudge.net/solution/63304444)
::: 源代码
```cpp
// by Gospel_rock
#include <algorithm>
#include <bits/stdc++.h>
#include <istream>
#include <ostream>
#include <queue>
#include <vector>
#define all(vec) vec.begin(),vec.end()
#define PB push_back
#define EB emplace_back
#define EM emplace
#define FI first
#define SE second
#define pct __builtin_popcountll
#define ctz __builtin_ctzll
#define SZ(a) ((long long) a.size())
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(var) cerr << #var <<":"<<var<<"\n";
#define cend cerr<<"\n-----------\n"
#define fsp(x) fixed<<setprecision(x)
#define minn(vec) *min_element(vec.begin(),vec.end())
#define maxx(vec) *max_element(vec.begin(),vec.end())
using namespace std;
#ifdef LOCAL
template<typename T> void _print(T x) { cerr << x; }
// 可以打印多层数组,但是格式不是很好
template<typename T> void _print(vector<T> v) { cerr << "[ "; for (T i : v) _print(i), cerr << " "; cerr << "]"; }
template<typename T> void _print(set<T> s) { cerr << "{ "; for (T i : s) _print(i), cerr << " "; cerr << "}"; }
template<typename T, typename U> void _print(pair<T, U> p) { cerr << "{"; _print(p.first); cerr << ", "; _print(p.second); cerr << "}"; }
template<typename T, typename U> void _print(map<T, U> m) { cerr << "{ "; for (auto &p : m) _print(p), cerr << " "; cerr << "}"; }
// 打印两层数组,格式好一些
template<typename T> void _print(vector<vector<T>> v){cerr<<"{\n";for (auto i : v) _print(i), cerr << "\n";cerr<<" }";}
#endif
using ll = long long;using ull = unsigned long long;
using ld=double;using LD=long double;
using i128 = __int128;
using pdd = pair<ld,ld>;using plb = pair<ll,bool>;
using pll = pair<ll,ll>;using vll=vector<ll>;using vb=vector<bool>;
using tll = tuple<ll,ll,ll>;using vii=vector<int>;
using vpll = vector<pll>;using vtll = vector<tll>;
using vdb = vector<ld>;using vc=vector<char>;
using arr3 = array<ll,3> ;using arr2 = array<ll,2>;
using CD=complex<double>;
static constexpr ll MAXN=(ll)1e6+10,INF=(ll)1e17+3; // 1e17+3是素数 1e18+9是素数
static constexpr ll mod=(ll)1e9+7; // 998244353;
static constexpr double eps=1e-8;const double pi=acos(-1.0);
ll N,M,Q,X,K,T,lT;
inline void __();
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// cin>>lT;
// while(lT--)
__();
return 0;
}
/*
*/
using Real = ld;
int sgn(Real x) {
if (-eps < x && x < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Point{
Real x,y;
Point(){}
Point(Real x,Real y):x(x),y(y){}
// & 是指只对左值起效果,不能对Point(1,2)这样的临时值
// friend Point& operator+=(Point &a,Point b){
// a.x+=b.x;
// a.y+=b.y;
// return a;
// }
friend Point operator +(Point a,Point b){
return Point(a.x+b.x,a.y+b.y);
}
friend Point operator -(Point a,Point b){
return Point(a.x-b.x,a.y-b.y);
}
friend bool operator <(Point a,Point b) {
return sgn(a.x-b.x)?a.x<b.x:a.y<b.y;
}
friend bool operator ==(Point a,Point b){
if(sgn(a.x-b.x)) return false;
if(sgn(a.y-b.y)) return false;
return true;
}
friend Point operator *(Point a,Real k){
return Point(a.x*k,a.y*k);
}
friend Point operator /(Point a,Real k){
return Point(a.x/k,a.y/k);
}
friend bool operator !=(Point a,Point b){
return !(a==b);
}
friend istream& operator >>(istream& is,Point &e){
Real a,b;is>>a>>b;
e=Point(a,b);
return is;
}
friend ostream &operator<<(ostream &os, Point p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
Real cross(Point a,Point b){
return a.x*b.y-a.y*b.x;
}
Real dot(Point a,Point b){
return a.x*b.x+a.y*b.y;
}
// 采用两点式
struct Line{
Point p,q;
Line(){}
Line(Point a,Point b):p(a),q(b) {}
friend bool operator<(Line a,Line b){
if(a.p!=b.p) return a.p<b.p;
return a.q<b.q;
}
friend bool operator==(Line a,Line b){
if(a.p!=b.p) return false;
if(a.q!=b.q) return false;
return true;
}
friend istream& operator>>(istream& is, Line& e) {
Real a,b,c,d;
is >> a >> b >> c >> d;
e = Line(Point(a,b),Point(c,d));
return is;
}
friend ostream&operator<<(ostream &os, Line l) {
return os << "<" << l.p << ", " << l.q << ">";
}
};
// p+tv=q+sw
// (p-q) x w+tv x w = 0
// t=-(p-q)x w/(vxw)
// 传入的是方向式 拿到的是两直线交点
Point getintersect(const Line &a,const Line &b){
Point p=a.p, v=a.q-a.p,q=b.p,w=b.q-b.p;
Point u=p-q;
ld t=cross(w,u)/cross(v,w);
return p+v*t;
}
bool isseginterline(Line seg,Line e){
if(sgn(cross(e.p-seg.p, e.q-seg.p))*sgn(cross(e.p-seg.q, e.q-seg.q))>0){
return false;
}
return true;
}
bool onseg(Point p,Line s){
return sgn(cross(p-s.p, p-s.q))==0 && sgn(dot(p-s.p,p-s.q))<=0;
}
struct Dis{
ll dis,idx;
friend bool operator <(Dis a,Dis b){
return a.dis>b.dis;
}
};
inline void __(){
cin>>N;
vector<Line> A(N);
vector<Point> node;
vector<Point> b1,b2,b3,b4;
auto add=[&](Point a){
if(sgn(a.x)==0){
b1.EB(a);
}else if(sgn(a.x-100)==0){
b2.EB(a);
}else if(sgn(a.y)==0){
b3.EB(a);
}else{
b4.EB(a);
}
};
FOR(i,0,N-1){
cin>>A[i];
add(A[i].p);
add(A[i].q);
}
FOR(i,0,N-1){
vector<Point> wp;
Line a=A[i];
FOR(j,0,N-1){
if(i==j) continue;
Line b=A[j];
if(isseginterline(a, b) && isseginterline(b, a)){
wp.PB(getintersect(a, b));
}
}
wp.EB(a.p);wp.EB(a.q);
sort(all(wp));
wp.resize(unique(all(wp))-wp.begin());
FOR(i,1,SZ(wp)-1){
Point mid=(wp[i]+wp[i-1])/2;
node.EB(mid);
}
}
sort(all(node));node.resize(unique(all(node))-node.begin());
Point sta;cin>>sta;node.EB(sta);
ll st=SZ(node);
// node.EB(Point(0,0));
// node.EB(Point(0,100));
// node.EB(Point(100,100));
// node.EB(Point(100,0));
auto addnode=[&](vector<Point> & a){
sort(all(a));
a.resize(unique(all(a))-a.begin());
FOR(i,1,SZ(a)-1){
Point mid=(a[i]+a[i-1])/2;
node.EB(mid);
}
};
b1.EB(0,0);b1.EB(0,100);
addnode(b1);
b2.EB(100,0);b2.EB(100,100);
addnode(b2);
b3.EB(0,0);b3.EB(100,0);
addnode(b3);
b4.EB(0,100);b4.EB(100,100);
addnode(b4);
auto check=[&](Line a)->bool {
bool ok=true;
FOR(i,0,SZ(A)-1){
Line t=A[i];
// if(t==a) continue;
if(onseg(a.p, t) && onseg(a.q, t)) return false;
if(isseginterline(t, a) && isseginterline(a, t)){
if(onseg(a.p, t) || onseg(a.q, t)) continue;
ok=false;
break;
}
}
return ok;
};
vector<vector<int> > g(SZ(node)+6);
FOR(i,0,SZ(node)-1){
FOR(j,i+1,SZ(node)-1){
if(check(Line(node[i],node[j]))){
g[i].EB(j);
g[j].EB(i);
}
}
}
// #ifdef LOCAL
// _print(g);
// _print(b1);
// debug(sta);
// debug(st);
// #endif
priority_queue<Dis> pq;
pq.push({0,st-1});
vector<ll> dist(SZ(node)+5,INF);
while (!pq.empty()) {
auto [dis,u]=pq.top();pq.pop();
if(dist[u]!=INF) continue;
dist[u]=dis;
for(auto v:g[u]){
#ifdef LOCAL
debug(v);
#endif
pq.push({dis+1,v});
}
}
ll ans=*min_element(dist.begin()+st,dist.end());
// #ifdef LOCAL
// _print(dist);
// #endif
cout<<"Number of doors = "<<ans<<"\n";
}
/*
AC
https://vjudge.net/solution/63304444
*/
```
:::
[https://vjudge.net/problem/UVA-754](https://vjudge.net/problem/UVA-754)
这道题目的UVA版本好像还加了数据,继续测一下。
搞了半天是格式问题,要换两次行。

[https://vjudge.net/solution/63313110](https://vjudge.net/solution/63313110)
::: 源代码
```cpp
// by Gospel_rock
#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <istream>
#include <ostream>
#include <queue>
#include <vector>
#define all(vec) vec.begin(),vec.end()
#define PB push_back
#define EB emplace_back
#define EM emplace
#define FI first
#define SE second
#define pct __builtin_popcountll
#define ctz __builtin_ctzll
#define SZ(a) ((long long) a.size())
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(var) cerr << #var <<":"<<var<<"\n";
#define cend cerr<<"\n-----------\n"
#define fsp(x) fixed<<setprecision(x)
#define minn(vec) *min_element(vec.begin(),vec.end())
#define maxx(vec) *max_element(vec.begin(),vec.end())
using namespace std;
#ifdef LOCAL
template<typename T> void _print(T x) { cerr << x; }
// 可以打印多层数组,但是格式不是很好
template<typename T> void _print(vector<T> v) { cerr << "[ "; for (T i : v) _print(i), cerr << " "; cerr << "]"; }
template<typename T> void _print(set<T> s) { cerr << "{ "; for (T i : s) _print(i), cerr << " "; cerr << "}"; }
template<typename T, typename U> void _print(pair<T, U> p) { cerr << "{"; _print(p.first); cerr << ", "; _print(p.second); cerr << "}"; }
template<typename T, typename U> void _print(map<T, U> m) { cerr << "{ "; for (auto &p : m) _print(p), cerr << " "; cerr << "}"; }
// 打印两层数组,格式好一些
template<typename T> void _print(vector<vector<T>> v){cerr<<"{\n";for (auto i : v) _print(i), cerr << "\n";cerr<<" }";}
#endif
using ll = long long;using ull = unsigned long long;
using ld=double;using LD=long double;
using i128 = __int128;
using pdd = pair<ld,ld>;using plb = pair<ll,bool>;
using pll = pair<ll,ll>;using vll=vector<ll>;using vb=vector<bool>;
using tll = tuple<ll,ll,ll>;using vii=vector<int>;
using vpll = vector<pll>;using vtll = vector<tll>;
using vdb = vector<ld>;using vc=vector<char>;
using arr3 = array<ll,3> ;using arr2 = array<ll,2>;
using CD=complex<double>;
static constexpr ll MAXN=(ll)1e6+10,INF=(ll)1e17+3; // 1e17+3是素数 1e18+9是素数
static constexpr ll mod=(ll)1e9+7; // 998244353;
static constexpr double eps=1e-9;const double pi=acos(-1.0);
ll N,M,Q,X,K,T,lT;
inline void __();
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>lT;
while(lT--)
__();
return 0;
}
/*
*/
using Real = ld;
int sgn(Real x) {
if (-eps < x && x < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Point{
Real x,y;
Point(){}
Point(Real x,Real y):x(x),y(y){}
// & 是指只对左值起效果,不能对Point(1,2)这样的临时值
// friend Point& operator+=(Point &a,Point b){
// a.x+=b.x;
// a.y+=b.y;
// return a;
// }
friend Point operator +(Point a,Point b){
return Point(a.x+b.x,a.y+b.y);
}
friend Point operator -(Point a,Point b){
return Point(a.x-b.x,a.y-b.y);
}
friend bool operator <(Point a,Point b) {
return sgn(a.x-b.x)?a.x<b.x:a.y<b.y;
}
friend bool operator ==(Point a,Point b){
if(sgn(a.x-b.x)) return false;
if(sgn(a.y-b.y)) return false;
return true;
}
friend Point operator *(Point a,Real k){
return Point(a.x*k,a.y*k);
}
friend Point operator /(Point a,Real k){
return Point(a.x/k,a.y/k);
}
friend bool operator !=(Point a,Point b){
return !(a==b);
}
friend istream& operator >>(istream& is,Point &e){
Real a,b;is>>a>>b;
e=Point(a,b);
return is;
}
friend ostream &operator<<(ostream &os, Point p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
Real cross(Point a,Point b){
return a.x*b.y-a.y*b.x;
}
Real dot(Point a,Point b){
return a.x*b.x+a.y*b.y;
}
// 采用两点式
struct Line{
Point p,q;
Line(){}
Line(Point a,Point b):p(a),q(b) {}
friend bool operator<(Line a,Line b){
if(a.p!=b.p) return a.p<b.p;
return a.q<b.q;
}
friend bool operator==(Line a,Line b){
if(a.p!=b.p) return false;
if(a.q!=b.q) return false;
return true;
}
friend istream& operator>>(istream& is, Line& e) {
Real a,b,c,d;
is >> a >> b >> c >> d;
e = Line(Point(a,b),Point(c,d));
return is;
}
friend ostream&operator<<(ostream &os, Line l) {
return os << "<" << l.p << ", " << l.q << ">";
}
};
// p+tv=q+sw
// (p-q) x w+tv x w = 0
// t=-(p-q)x w/(vxw)
// 传入的是方向式 拿到的是两直线交点
Point getintersect(const Line &a,const Line &b){
Point p=a.p, v=a.q-a.p,q=b.p,w=b.q-b.p;
Point u=p-q;
ld t=cross(w,u)/cross(v,w);
return p+v*t;
}
bool seginterline(Line seg,Line e){
if(sgn(cross(e.p-seg.p, e.q-seg.p))*sgn(cross(e.p-seg.q, e.q-seg.q))>0){
return false;
}
return true;
}
bool seginterseg(Line a,Line b){
// auto [s,e]=a;
// auto [s2,e2]=b;
// Real A=max(s.x,e.x),AA=min(s2.x,e2.x);
// Real B=max(s.y,e.y),BB=min(s2.y,e2.y);
// if(sgn(A-AA)<0 && sgn(B-BB)<0){
// return false;
// }
if(seginterline(a, b) && seginterline(b, a)){
return true;
}
return false;
}
bool onseg(Point p,Line s){
return sgn(cross(p-s.p, p-s.q))==0 && sgn(dot(p-s.p,p-s.q))<=0;
}
struct Dis{
ll dis,idx;
friend bool operator <(Dis a,Dis b){
return a.dis>b.dis;
}
};
inline void __(){
cin>>N;
vector<Line> A(N);
vector<Point> node;
vector<Point> b1,b2,b3,b4;
auto add=[&](Point a){
if(sgn(a.x)==0){
b1.EB(a);
}else if(sgn(a.x-100)==0){
b2.EB(a);
}else if(sgn(a.y)==0){
b3.EB(a);
}else{
b4.EB(a);
}
};
FOR(i,0,N-1){
cin>>A[i];
add(A[i].p);
add(A[i].q);
}
FOR(i,0,N-1){
vector<Point> wp;
Line a=A[i];
FOR(j,0,N-1){
if(i==j) continue;
Line b=A[j];
if(sgn(cross(a.p-a.q,b.p-b.q))==0) continue;
if(seginterseg(a, b)){
wp.PB(getintersect(a, b));
}
}
wp.EB(a.p);wp.EB(a.q);
sort(all(wp));
wp.resize(unique(all(wp))-wp.begin());
FOR(i,1,SZ(wp)-1){
Point mid=(wp[i]+wp[i-1])/2;
node.EB(mid);
}
}
sort(all(node));node.resize(unique(all(node))-node.begin());
Point sta;cin>>sta;node.EB(sta);
ll st=SZ(node);
// node.EB(Point(0,0));
// node.EB(Point(0,100));
// node.EB(Point(100,100));
// node.EB(Point(100,0));
auto addnode=[&](vector<Point> & a){
sort(all(a));
a.resize(unique(all(a))-a.begin());
FOR(i,1,SZ(a)-1){
Point mid=(a[i]+a[i-1])/2;
node.EB(mid);
}
};
b1.EB(0,0);b1.EB(0,100);
addnode(b1);
b2.EB(100,0);b2.EB(100,100);
addnode(b2);
b3.EB(0,0);b3.EB(100,0);
addnode(b3);
b4.EB(0,100);b4.EB(100,100);
addnode(b4);
auto check=[&](Line a)->bool {
bool ok=true;
FOR(i,0,SZ(A)-1){
Line t=A[i];
// if(t==a) continue;
if(onseg(a.p, t) && onseg(a.q, t)) return false;
if(seginterseg(a, t)){
if(onseg(a.p, t) || onseg(a.q, t)) continue;
ok=false;
break;
}
}
return ok;
};
vector<vector<int> > g(SZ(node)+6);
FOR(i,0,SZ(node)-1){
FOR(j,i+1,SZ(node)-1){
if(check(Line(node[i],node[j]))){
g[i].EB(j);
g[j].EB(i);
}
}
}
// #ifdef LOCAL
// _print(g);
// _print(b1);
// debug(sta);
// debug(st);
// #endif
priority_queue<Dis> pq;
pq.push({0,st-1});
vector<ll> dist(SZ(node)+5,INF);
while (!pq.empty()) {
auto [dis,u]=pq.top();pq.pop();
if(dist[u]!=INF) continue;
dist[u]=dis;
for(auto v:g[u]){
pq.push({dis+1,v});
}
}
ll ans=*min_element(dist.begin()+st,dist.end());
// #ifdef LOCAL
// _print(dist);
// #endif
cout<<"Number of doors = "<<ans<<"\n";
if(lT!=0) cout<<"\n";
}
/*
https://vjudge.net/problem/UVA-754
2
0 100 50 0
100 100 50 0
50 99
*/
```
:::
## 心路历程(WA,TLE,MLE……)