C 天际线算法
如何找到此图像中围绕轮廓的折线的顶点 上述示例的一个可能输入为: WIDTH HEIGHT POSITION 3 9 17 5 9 9 12 4 8 3 11 3 10 7 1 2 3 19 宽高位置 3 9 17 5 9 9 12 4 8 3 11 3 10 7 1 2 3 19 所以对于这个例子,解决方案是 [(1, 0), (1, 7), (3, 7), (3, 11), (6, 11), (6, 7), (9, 7), (9, 9), (14, 9), (14, 4), (17, 4), (17, 9), (20, 9), (20, 3), (21, 3), (21, 0)] [(1, 0), (1, 7), (3, 7), (3, 11), (6, 11), (6, 7), (9, 7), (9, 9), (14, 9), (14, 4), (17, 4), (17, 9), (20, 9), (20, 3), (21, 3), (21, 0)]C 天际线算法,c,algorithm,C,Algorithm,如何找到此图像中围绕轮廓的折线的顶点 上述示例的一个可能输入为: WIDTH HEIGHT POSITION 3 9 17 5 9 9 12 4 8 3 11 3 10 7 1 2 3 19 宽高位置 3 9 17 5 9 9 12 4 8 3
在天真的情况下,这似乎不是一个非常困难的算法。您知道输入大小是否会变大/有多大吗 我最初的尝试是:尝试从左向右移动。首先拾取具有存在于原点线上的最左侧边的块。爬到山顶。查找在当前块的当前点和右上角点之间具有左边缘的所有块。在该集合中,选择最接近的(但检查边缘情况,不使用双关语)。如果集合为空,开始沿着块的右侧向下移动,寻找可能拦截的其他块 基本上这就是你用眼睛追踪它的方式 您可以通过保持已排序的列表,然后搜索列表,而不是查找集合并四处挖掘,来进行一些简单的优化。例如,可以保留4个已排序的块列表,每个列表按其中一侧的x或y坐标排序
如果你有很多很多块,你可以考虑使用多维数据结构来进一步组织信息。
这很简单。制作一个长度为X轴的数组,初始化为0。读取输入时,如果高度>=数组中该位置的当前值,请将高度写入该数组
然后在数组上循环,每次值改变时,它就是一个顶点 基本上:int heights[SIZE] = {0};
int i, width, pos, height, prev = -1;
while (scanf("%d %d %d", &width, &height, &pos) == 3) {
for (i = 0; i < width; ++i) {
if (heights[pos+i] < height)
heights[pos+i] = height;
}
}
for (i = 0; i < SIZE; ++i) {
if (heights[i] != prev) {
printf("(%d,%d) ", i+1, heights[i]);
prev = heights[i];
}
}
printf("\n");
int heights[SIZE]={0};
整数i,宽度,位置,高度,上一个=-1;
而(扫描频率(“%d%d%d”、&宽度、高度和位置)==3){
对于(i=0;i
我创建了一个Java类来尝试解决这个问题。该类包括用于生成、求解和打印数据集的方法。我还没有进行全面测试,可能还有一些bug。此外,我的解决方案可能会变得不必要的复杂,但它的设计(理论上)适用于非离散高度和坐标值
import java.util.Random;
public class Skyline {
private int[][] buildings;
private int[][] skyline;
private int maxLength;
private int maxHeight;
public Skyline(int buildings, int maxLength, int maxHeight) {
this.maxLength = maxLength;
this.maxHeight = maxHeight;
makeRandom(buildings);
}
public Skyline(int[][] buildings, int dimensions) {
this.maxLength = maxLength;
this.maxHeight = maxHeight;
this.buildings = buildings;
}
public void makeRandom(int buildings) {
this.buildings = new int[buildings][3];
Random rand = new Random();
for(int i = 0; i < buildings; i++) {
int start = rand.nextInt(maxLength-3);
int end = rand.nextInt(maxLength - start - 1) + start + 1;
int height = rand.nextInt(maxHeight-1) + 1;
this.buildings[i][0] = start;
this.buildings[i][1] = height;
this.buildings[i][2] = end;
}
boolean swapped = true;
while(swapped) {
swapped = false;
for(int i = 0; i < this.buildings.length-1; i++) {
if(this.buildings[i][0] > this.buildings[i+1][0]) {
swapped = true;
int[] temp = this.buildings[i];
this.buildings[i] = this.buildings[i+1];
this.buildings[i+1] = temp;
}
}
}
// this.buildings[0][0] = 2;
// this.buildings[0][1] = 3;
// this.buildings[0][2] = 8;
}
public void printBuildings() {
print(this.buildings, false);
}
public void printSkyline() {
print(this.buildings, true);
}
public void print(int[][] buildings, boolean outline) {
char[][] str = new char[this.maxLength][this.maxHeight];
for(int i = 0; i < this.maxLength; i++) {
for(int j = 0; j < this.maxHeight; j++) {
str[i][j] = '.';
}
}
for(int i = 0; i < buildings.length; i++) {
int start = buildings[i][0];
int height = buildings[i][1];
int end = buildings[i][2];
//print the starting vertical
for(int j = 0; j < height; j++) {
if(outline) str[start][j] = str[start][j] == '|' ? '.' : '|';
else str[start][j] = '|';
}
//print the ending vertical
for(int j = 0; j < height; j++) {
if(outline) str[end][j] = str[end][j] == '|' ? '.' : '|';
else str[end][j] = '|';
}
//print the horizontal
if(height > 0) {
for(int j = start; j <= end; j++) {
str[j][height] = str[j][height] == '|' ? '|' : '-';
}
}
}
for(int i = maxHeight-1; i >= 0; i--) {
for(int j = 0; j < maxLength; j++) {
System.out.print(str[j][i]);
}
System.out.println();
}
System.out.println();
}
public void solveSkyline() {
for(int i = 0; i < buildings.length; i++) {
boolean reduced = true;
while(reduced) {
reduced = false;
for(int j = i+1; j < buildings.length; j++) {
if(buildings[j][0] < buildings[i][2] && buildings[j][1] > buildings[i][1] && buildings[j][2] >= buildings[i][2]) { //if intersecting building is taller, and longer
buildings[i][2] = buildings[j][0];
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][1] <= buildings[i][1] && buildings[j][2] >= buildings[i][2]) { //intersecting building is shorter, but longer
buildings[j][0] = buildings[i][2];
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][1] > 0 && buildings[j][1] < buildings[i][1] && buildings[j][2] <= buildings[i][2]) { //building is invisible, so ignore it
buildings[j][1] = 0;
reduced = true;
break;
} else if(buildings[j][0] < buildings[i][2] && buildings[j][2] <= buildings[i][2] && buildings[j][1] > buildings[i][1]) {
int[] newBuilding = new int[]{buildings[j][2], buildings[i][1], buildings[i][2]};
int[][] newBuildings = new int[buildings.length+1][3];
boolean inserted = false;
buildings[i][2] = buildings[j][0];
for(int k = 0; k < buildings.length; k++) {
if(inserted == false) {
if(newBuilding[0] < buildings[k][0]) {
newBuildings[k] = newBuilding;
newBuildings[k+1] = buildings[k];
inserted = true;
} else {
newBuildings[k] = buildings[k];
}
}
if(inserted == false && k == buildings.length - 1) {
newBuildings[k+1] = newBuilding;
} else {
newBuildings[k+1] = buildings[k];
}
}
buildings = newBuildings;
reduced = true;
break;
}
}
}
}
}
public static void main(String args[]) {
Skyline s = new Skyline(5, 100, 10);
s.printBuildings();
s.solveSkyline();
s.printBuildings();
s.printSkyline();
}
}
import java.util.Random;
公共级天际线{
私人int[]大厦;
私人int[][]天际线;
私有整数最大长度;
私有整数最大高度;
公共天际线(int建筑物、int最大长度、int最大高度){
this.maxLength=maxLength;
this.maxHeight=maxHeight;
随机(建筑物);
}
公共天际线(内部[]建筑物,内部尺寸){
this.maxLength=maxLength;
this.maxHeight=maxHeight;
这是指建筑物=建筑物;
}
公共建筑(内部建筑){
this.buildings=新国际[建筑物][3];
Random rand=新的Random();
对于(int i=0;i<建筑物;i++){
int start=rand.nextInt(maxLength-3);
int end=rand.nextInt(maxLength-start-1)+start+1;
int height=rand.nextInt(maxHeight-1)+1;
本.建筑物[i][0]=起点;
这.建筑物[i][1]=高度;
本.建筑物[i][2]=终点;
}
布尔交换=真;
while(交换){
交换=假;
对于(int i=0;ithis.buildings[i+1][0]){
交换=真;
int[]temp=该建筑物[i];
this.buildings[i]=this.buildings[i+1];
这是指建筑物[i+1]=温度;
}
}
}
//这.建筑物[0][0]=2;
//这.建筑物[0][1]=3;
//这.建筑物[0][2]=8;
}
公共建筑物(){
打印(本页为建筑,假);
}
公共天际线(){
打印(这是真实的建筑物);
}
公共空白打印(int[][]建筑物,布尔轮廓){
char[][]str=new char[this.maxLength][this.maxHeight];
for(int i=0;i0){
对于(int j=start;j=0;i--){
对于(int j=0;j建筑物[i][1]&建筑物[j][2]>=建筑物[i][2]){//如果相交的建筑物更高、更长
建筑物[
points=[]
for building in buildings:
points+=[[building[0],building[2]]]
points+=[[building[1],-building[2]]] # the negative sign means this point is a right point
points=sorted(points, key=lambda x: x[0])
moving, active, res, current=0, [0], [],-1
while moving<len(points):
i=moving
while i<=len(points):
if i<len(points) and points[i][0]==points[moving][0]:
if points[i][1]>0:
active+=[points[i][1]]
if points[i][1]>current:
current=points[i][1]
if len(res)>0 and res[-1][0]==points[i][0]:
res[-1][1]=current
else:
res+=[[points[moving][0], current]]
else:
active.remove(-points[i][1]) #remove height of the lines than have been finished with scanning
i+=1
else:
break
if max(active)<current:
current=max(active)
res+=[[points[moving][0], current]]
moving=i
return res
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
// The final result.
vector<pair<int, int>> result;
// To hold information about the buildings
std::set<BuildingInformation> buildingInformation;
// Go through each building, and store information about the start and end heights.
for ( vector<vector<int>>::iterator buildingIt = buildings.begin( ); buildingIt != buildings.end( ); ++buildingIt ) {
BuildingInformation buildingStart;
buildingStart.x = (*buildingIt)[0];
buildingStart.h = (*buildingIt)[2];
buildingStart.StartOrEnd = Start;
buildingInformation.insert(buildingStart);
buildingStart.x = (*buildingIt)[1];
buildingStart.StartOrEnd = End;
buildingInformation.insert(buildingStart);
}
// Keep track of the current height.
int currentHeight = 0;
// A map of active building heights against number of buildings (to handle multiple buildings overlapping with same height).
// As it is a map, it'll be sorted by key, which is the height.
std::map<int, int> heights;
// Go through each building information that we generated earlier.
for ( std::set<BuildingInformation>::iterator it = buildingInformation.begin( ); it != buildingInformation.end( ); ++it ) {
if ( it->StartOrEnd == Start ) {
// This is a start point, do we have this height already in our map?
if ( heights.find( it->h ) != heights.end( ) ) {
// Yes, increment count of active buildings with this height/
heights[ it->h ] += 1;
} else {
// Nope, add this building to our map.
heights[ it->h ] = 1;
}
// Check if building height is taller than current height.
if ( it->h > currentHeight ) {
// Update current height and add marker to results.
currentHeight = it->h;
result.push_back( pair<int, int>( it->x, currentHeight ) );
}
} else {
// This is an end point, get iterator into our heights map.
std::map<int, int>::iterator heightIt = heights.find( it->h );
// Reduce by one.
heightIt->second -= 1;
// If this was the last building of the current height in the map...
if ( heightIt->second == 0 ) {
// Remove from heights map.
heights.erase( heightIt );
// If our height was the current height...
if ( it->h == currentHeight ) {
// If we have no more active buildings...
if ( heights.size( ) == 0 ) {
// Current height is zero.
currentHeight = 0;
} else {
// Otherwise, get iterator to one past last.
heightIt = heights.end( );
// Go back to get last valid iterator.
--heightIt;
// Store current height.
currentHeight = heightIt->first;
}
// Add marker to results.
result.push_back( pair<int, int>( it->x, currentHeight ) );
}
}
}
}
return result;
}
private:
// Is this a building start or end?
enum BuildingStartOrEnd
{
Start = 0,
End
};
// Information about building, there are two of these for each building, one for start, one for end.
struct BuildingInformation
{
int x;
int h;
BuildingStartOrEnd StartOrEnd;
// The ordering algorithm for the key, the rules we want to implement is keys are put in X order, and
// in the case of a tie (x values the same), we want Start pieces to come before End pieces (this is
// to handle cases where an old building ends and a new building begins on same X index, in which case
// we want to process the new start before processing the old end), however if we have two Start pieces
// at the same index, we wish to favour taller pieces (in this scenario we want to add a marker for the
// tallest building), finally if we have two End pieces at the same index, we wish to prefer lower
// pieces, as when multiple buildings end, we only want to add one result for the ultimate lowest point.
bool operator < ( const BuildingInformation & rhs ) const
{
if ( x == rhs.x )
{
if ( StartOrEnd == rhs.StartOrEnd ) {
if ( StartOrEnd == Start )
return h > rhs.h;
else
return h < rhs.h;
} else {
return StartOrEnd < rhs.StartOrEnd;
}
}
return x < rhs.x;
}
};
};