Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 天际线算法_C_Algorithm - Fatal编程技术网

C 天际线算法

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

如何找到此图像中围绕轮廓的折线的顶点

上述示例的一个可能输入为:

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)]
在天真的情况下,这似乎不是一个非常困难的算法。您知道输入大小是否会变大/有多大吗

我最初的尝试是:尝试从左向右移动。首先拾取具有存在于原点线上的最左侧边的块。爬到山顶。查找在当前块的当前点和右上角点之间具有左边缘的所有块。在该集合中,选择最接近的(但检查边缘情况,不使用双关语)。如果集合为空,开始沿着块的右侧向下移动,寻找可能拦截的其他块

基本上这就是你用眼睛追踪它的方式

您可以通过保持已排序的列表,然后搜索列表,而不是查找集合并四处挖掘,来进行一些简单的优化。例如,可以保留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;
        }
    };
};