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
|
#include <iostream>
#include <sstream>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;
//==========================================================
struct Rectangle
{
int L, R, H; // left, right, height
};
//==========================================================
istream & operator >> ( istream &str, Rectangle &rect ) // Stream extraction for a rectangle
{
int W;
str >> W;
if ( W < 0 ) // Put the stream in a failed state
{
str.setstate( ios::failbit );
}
else
{
str >> rect.H >> rect.L;
rect.R = rect.L + W;
}
return str;
}
//==========================================================
vector<pair<int,int>> skyline( vector<Rectangle> buildings ) // Returns the skyline as (x,y) pairs
{
vector<pair<int,int>> perimeter;
if ( buildings.size() == 0 ) return perimeter; // Trivial case
// Put buildings in order of height, tallest first
sort( buildings.begin(), buildings.end(), []( Rectangle r, Rectangle s ){ return r.H > s.H;} );
vector<Rectangle> visible; // To hold non-overlapping visible sub-blocks
// Tallest building (always seen)
visible.push_back( buildings[0] );
// Deal with each of the remaining buildings, collecting what can be seen into visible()
for ( int i = 1; i < buildings.size(); i++ )
{
vector<Rectangle> oneBuilding, temp = { buildings[i] };
// Add any visible parts of this rectangle to visible()
for ( int j = 0; j < visible.size(); j++ )
{
oneBuilding = temp;
temp.clear();
for ( Rectangle rect : oneBuilding )
{
if ( rect.R < visible[j].L || rect.L > visible[j].R ) // Completely visible
{
temp.push_back( rect );
}
else if ( rect.L < visible[j].L && rect.R > visible[j].R )
{
temp.push_back( { rect.L, visible[j].L, rect.H } ); // Two ends visible
temp.push_back( { visible[j].R, rect.R, rect.H } ); //
}
else if ( rect.L < visible[j].L )
{
temp.push_back( { rect.L, visible[j].L, rect.H } ); // Left end visible
}
else if ( rect.R > visible[j].R )
{
temp.push_back( { visible[j].R, rect.R, rect.H } ); // Right end visible
}
}
}
if ( !temp.empty() ) visible.insert( visible.end(), temp.begin(), temp.end() );
}
// Sort visible() by position
sort( visible.begin(), visible.end(), []( Rectangle r, Rectangle s ){ return r.L < s.L; } );
// Convert visible() to a skyline
perimeter.push_back( { visible[0].L, 0 } ); // Start point
perimeter.push_back( { visible[0].L, visible[0].H } ); // Top-left of 0-th block
for ( int i = 0; i < visible.size() - 1; i++ )
{
perimeter.push_back( { visible[i].R, visible[i].H } ); // Right of i-th horizontal
if ( visible[i+1].L > visible[i].R ) // If gap in skyline ...
{
perimeter.push_back( { visible[i].R, 0 } ); // Go down to floor
perimeter.push_back( { visible[i+1].L, 0 } ); // Go to start of (i+1)-th block
}
perimeter.push_back( { visible[i+1].L, visible[i+1].H } ); // Top-left of (i+1)-th block
}
int i = visible.size() - 1;
perimeter.push_back( { visible[i].R, visible[i].H } ); // Last horizontal
perimeter.push_back( { visible[i].R, 0 } ); // Final point at floor
return perimeter;
}
//==========================================================
int main()
{
stringstream in( " 3 11 3 "
"10 7 1 "
" 5 9 9 "
"12 4 8 "
" 3 9 17 "
" 2 3 19 "
" -1 " );
vector<Rectangle> buildings;
Rectangle rect;
while( in >> rect ) buildings.push_back( rect );
vector<pair<int,int>> perimeter = skyline( buildings );
cout << "Skyline is (x,y):\n";
for ( auto e : perimeter ) cout << e.first << '\t' << e.second << '\n';
}
//==========================================================
|