0% found this document useful (0 votes)
14 views6 pages

A

The document is a C++ program that implements a solution for finding the shortest path in a grid while considering visibility constraints based on height. It uses geometric calculations for line intersections and visibility checks to determine if one point can see another in a 2D space. The program includes functions for handling geometric operations, caching intersection results, and performing a breadth-first search to find the shortest path between two specified points.

Uploaded by

richardq343
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views6 pages

A

The document is a C++ program that implements a solution for finding the shortest path in a grid while considering visibility constraints based on height. It uses geometric calculations for line intersections and visibility checks to determine if one point can see another in a 2D space. The program includes functions for handling geometric operations, caching intersection results, and performing a breadth-first search to find the shortest path between two specified points.

Uploaded by

richardq343
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

#include <bits/stdc++.

h>
using namespace std;

using ll = long long;


using pi = pair<int, int>;
#define mp make_pair
#define f first
#define s second

#define tcT template<class T


tcT> using V = vector<T>;
using vi = V<int>;
using vpi = V<pi>;
using vb = V<bool>;

#define sz(x) int((x).size())


#define all(x) begin(x), end(x)
#define pb push_back
#define bk back()
#define ins insert

using db = double;

const int MOD = 1e9+7;

tcT> bool ckmin(T& a, const T& b){


return b < a ? a = b, 1 : 0;
}

tcT> bool ckmax(T& a, const T& b){


return a < b ? a = b, 1 : 0;
}

vi dx = vi{1, 0, -1, 0};


vi dy = vi{0, 1, 0, -1};

using T = db;
const db EPS = 1e-9;
using P = pair<T, T>; using vP = V<P>; using Line = pair<P, P>;
int sgn(T a){ return (a > EPS) - (a < -EPS);}
T sq(T a) { return a*a; }
T norm(P p){
return sq(p.f)+sq(p.s);
}
T abs(P p){
return sqrt(norm(p));
}

P operator+(P l, P r){
return P(l.f+r.f, l.s+r.s);
}
P operator-(P l, P r){
return P(l.f-r.f, l.s-r.s);
}
P operator*(P l, T r){
return P(l.f*r, l.s*r);
}
P operator/(P l, T r){
return P(l.f/r, l.s/r);
}

T cross(const P& a, const P& b){


return a.f*b.s-a.s*b.f;
}

T cross(const P& p, const P& a, const P& b){


return cross(a-p, b-p);
}

T dot(const P& a, const P& b){


return a.f*b.f+a.s*b.s;
}
T dot(const P& p, const P& a, const P& b){
return dot(a-p, b-p);
}

ostream& operator<<(ostream& os, P p){


return os << "(" << p.f << "," << p.s << ")";
}

bool onSeg(const P& p, const Line& l){


return sgn(cross(l.f, l.s, p)) == 0 && sgn(dot(p, l.f, l.s)) <= 0;
}

vP strictIsect(const Line& a, const Line& b){


T a0 = cross(a.f, a.s, b.f), a1 = cross(a.f, a.s, b.s);
T b0 = cross(b.f, b.s, a.f), b1 = cross(b.f, b.s, a.s);
if(sgn(a0)*sgn(a1) < 0 && sgn(b0)*sgn(b1) < 0)
return {(b.s*a0-b.f*a1)/(a0-a1)};
return {};
}

vP segIsect(const Line& a, const Line& b){


vP v = strictIsect(a, b); if(sz(v)) return v;
set<P> s;
#define i(x, y) if(onSeg(x, y)) s.ins(x);
i(a.f, b); i(a.s, b); i(b.f, a); i(b.s, a);
return {all(s)};
}

const int mx = 205;


const bool DEBUG = false;
int Z[mx][mx];

pair<pi, db> cache_all_isects[mx][mx][820];

int cache_size[mx][mx];

int not_cached = 0;
void getAllIsects(pi pos_second){
assert(pos_second.f >= pos_second.s && 0 <= pos_second.f && 0 <= pos_second.s);
// if(cache_all_isects.count(pos_second)) return cache_all_isects[pos_second.f]
[pos_second.s];

if(pos_second == mp(0, 0)){


// cache_all_isects[pos_second.f][pos_second.s] = {};
return;
}

pi pos_first = mp(0, 0);


Line l = mp(pos_first, pos_second);

db slop = pos_second.s/pos_second.f;
db tot_dist = abs(l.s-l.f);

pi cur_point = mp(0, 0);


while(cur_point != pos_second){
// cout << cur_point.f << " " << cur_point.s << "\n";
// cout << "DEST: " << pos_second.f << " " << pos_second.s << "\n";
P upper_right = mp(cur_point.f+0.5, cur_point.s+0.5);
int SGN = sgn(cross(pos_first, pos_second, upper_right));
pi next_point = cur_point;
P isect_point = upper_right;
if(SGN == 0){

isect_point = upper_right;

next_point.f++;
next_point.s++;
}
else if(SGN == 1){ // go right
db x = cur_point.f+0.5;
isect_point = mp(x, slop*x);
next_point.f++;
}
else if(SGN == -1){
// Line horz = mp(mp(cur_point.f-0.5, cur_point.s+0.5),
mp(cur_point.f+0.5, cur_point.s+0.5));
//y = cur_point.s+0.5
db y = cur_point.s+0.5;
isect_point = mp(y/slop, y);

next_point.s++;
}

db dist = abs(isect_point-l.f);
db frac = dist/tot_dist;

cache_all_isects[pos_second.f][pos_second.s][cache_size[pos_second.f]
[pos_second.s]] = mp(cur_point, frac);
cache_size[pos_second.f][pos_second.s]++;
cache_all_isects[pos_second.f][pos_second.s][cache_size[pos_second.f]
[pos_second.s]] = mp(next_point, frac);
cache_size[pos_second.f][pos_second.s]++;

cur_point = next_point;

bool isVisible(pi pos_first, pi pos_second){ //can pos_first see pos_second?


P point_first = pos_first;
P point_second = pos_second;
db height_first = Z[pos_first.f][pos_first.s]+0.5;
db height_second = Z[pos_second.f][pos_second.s]+0.5;

pi pos_second_normalized = mp(pos_second.f-pos_first.f, pos_second.s-


pos_first.s);
bool neg_x = pos_second_normalized.f < 0; if(neg_x) pos_second_normalized.f = -
pos_second_normalized.f;
bool neg_y = pos_second_normalized.s < 0; if(neg_y) pos_second_normalized.s = -
pos_second_normalized.s;
bool swap_xy = pos_second_normalized.f < pos_second_normalized.s; if(swap_xy)
swap(pos_second_normalized.f, pos_second_normalized.s);

// cout << pos_second_normalized.f << " " << pos_second_normalized.s << "\n";
cout.flush();
// assert(cache_all_isects.count(pos_second_normalized));

for(int i = 0; i < cache_size[pos_second_normalized.f]


[pos_second_normalized.s]; i++){
pi cand = cache_all_isects[pos_second_normalized.f]
[pos_second_normalized.s][i].f;
db frac = cache_all_isects[pos_second_normalized.f]
[pos_second_normalized.s][i].s;
if(swap_xy){
swap(cand.f, cand.s);
}
if(neg_x){
cand.f = -cand.f;
}
if(neg_y){
cand.s = -cand.s;
}
cand.f+=pos_first.f;
cand.s+=pos_first.s;

//check this candidate


// db tot_dist = abs(point_second-point_first);
db h = height_first+frac*(height_second-height_first);
if(h+EPS < Z[cand.f][cand.s]){
//BAD
return false;
}
}
return true;
}

void solve(int tc){


// cout << "SOLVING: " << tc << "\n"; cout.flush();
int P, Q;
if(DEBUG){
if(tc <= 5){
P = 200; Q = 200;
}
else{
P = 50; Q = 50;
}
}
else{
cin >> P >> Q;
}
if(DEBUG){
for(int i = 1; i <= P; i++){
for(int j = 1; j <= Q; j++){
Z[i][j] = 0;
}
}
}
else{
for(int i = 1; i <= P; i++){
for(int j = 1; j <= Q; j++){

cin >> Z[i][j];


}
}
}

V<vb> visible(P+2, vb(Q+2, false));

int R1, C1, R2, C2;

if(DEBUG){
R1 = 1;
C1 = 1;
R2 = P;
C2 = Q;
}
else{
cin >> R1 >> C1 >> R2 >> C2;
}

for(int i = 1; i <= P; i++){


for(int j = 1; j <= Q; j++){
if(isVisible(mp(R1, C1), mp(i, j)) || isVisible(mp(R2, C2), mp(i, j))){
visible[i][j] = true;
}
}
}

V<vi> dist(P+2, vi(Q+2, MOD));

queue<pair<int, pi>> q;
ckmin(dist[R1][C1], 0);
q.push(mp(dist[R1][C1], mp(R1, C1)));
while(sz(q)){
int dis = q.front().f;
pi pos = q.front().s;
// cout << pos.f << " " << pos.s << " " << dis << "\n";
q.pop();
assert(1 <= pos.f && pos.f <= P && 1 <= pos.s && pos.s <= Q);
if(dist[pos.f][pos.s] < dis) continue;

for(int d = 0; d < 4; d++){


int new_x = pos.f+dx[d];
int new_y = pos.s+dy[d];
//check if possible to go here
assert(visible[pos.f][pos.s]);
if(!visible[new_x][new_y]) continue;
if(Z[new_x][new_y] > Z[pos.f][pos.s]+1 || Z[new_x][new_y] < Z[pos.f]
[pos.s]-3){
//can't ascend more than 1 or descend more than 3
continue;
}

if(ckmin(dist[new_x][new_y], dis+1)){
// cout << "CKMIN: " << new_x << " " << new_y << " " << d+1 << "\
n";
// cout << "CUR HEIGHT: " << Z[pos.f][pos.s] << "\n";
// cout << "HEIGHT: " << Z[new_x][new_y] << "\n";
q.push(mp(dist[new_x][new_y], mp(new_x, new_y)));
}
}
}

int M = dist[R2][C2];
if(M >= MOD){
cout << "Mission impossible!" << "\n";
}
else{
cout << "The shortest path is " << M << " steps long." << "\n";
}

int main(){
cin.tie(0)->sync_with_stdio(0);

clock_t BEG = clock();


for(int i = 0; i <= 200; i++){
for(int j = 0; j <= i; j++){
getAllIsects(mp(i, j));
}
}
// cout << "TIME: " << db(clock()-BEG)/db(CLOCKS_PER_SEC) << "\n";
cout.flush();
// cout << "NOT_CACHED: " << not_cached << "\n";

int T;
if(DEBUG){
T = 300;
}
else{
cin >> T;
}
for(int t = 1; t <= T; t++){
solve(t);
}
}

You might also like