简体   繁体   English

TopCoder上的FlowerGarden prolble如何成为DP-one?

[英]How is the FlowerGarden pr0blem on TopCoder a DP-one?

I'm reading this excellent tutorial by Dumitru on DP based problems here . 我被杜米特鲁基于DP问题阅读本优秀教程这里 And I'm trying to come up with a DP based approach for the FlowerGarden problem mentioned in the list of 1D DP problems. 我正在尝试针对1D DP问题列表中提到的FlowerGarden问题提出基于DP的方法。

I can only think of a non-DP solution that would involve initially sorting the flowers in an order and then reordering them based on different condition checks mentioned in the problem. 我只能想到一个非DP解决方案,它将涉及最初按顺序对花进行排序,然后根据问题中提到的不同条件检查对它们进行重新排序。 That doesn't classify as DP, does it? 这不归类为DP,是吗?

The editorial also doesn't mention anything about DP. 社论也没有提到关于DP的任何事情。 Could anyone, by any chance, point me to a proper DP-based solution to this problem? 任何人都可以指出我对这个问题采用适当的基于DP的解决方案吗?

Thanks! 谢谢!

Edit: 编辑:

I didn't realize the link would require registration. 我没有意识到链接需要注册。 This is the problem: 这就是问题:

Problem Statement You are planting a flower garden with bulbs to give you joyous flowers throughout the year. 问题陈述您正在种植带有灯泡的花园,全年为您提供欢乐的花朵。 However, you wish to plant the flowers such that they do not block other flowers while they are visible. 但是,您希望种植花卉,使它们在可见时不会阻挡其他花朵。

You will be given a int[] height, a int[] bloom, and a int[] wilt. 您将获得int []高度,int [] bloom和int [] wilt。 Each type of flower is represented by the element at the same index of height, bloom, and wilt. 每种类型的花由高度,绽放和枯萎的相同指数的元素表示。 height represents how high each type of flower grows, bloom represents the morning that each type of flower springs from the ground, and wilt represents the evening that each type of flower shrivels up and dies. 高度代表每种花朵生长的高度,绽放代表每种花朵从地面弹出的早晨,而枯萎代表着每种花朵枯萎死亡的夜晚。 Each element in bloom and wilt will be a number between 1 and 365 inclusive, and wilt[i] will always be greater than bloom[i]. bloom和wilt中的每个元素都是1到365之间的数字,wilt [i]总是大于bloom [i]。 You must plant all of the flowers of the same type in a single row for appearance, and you also want to have the tallest flowers as far forward as possible. 你必须将所有相同类型的花朵种植在一排以便于外观,并且你还希望尽可能地将最高的花朵放在最前面。 However, if a flower type is taller than another type, and both types can be out of the ground at the same time, the shorter flower must be planted in front of the taller flower to prevent blocking. 但是,如果花型比其他类型高,并且两种类型可以同时离开地面,则必须在较高花的前面种植较短的花以防止阻塞。 A flower blooms in the morning, and wilts in the evening, so even if one flower is blooming on the same day another flower is wilting, one can block the other. 一朵花在早晨开花,在晚上枯萎,所以即使一朵花在同一天开花,另一朵花在枯萎,一朵可以阻挡另一朵花。

You should return a int[] which contains the elements of height in the order you should plant your flowers to acheive the above goals. 你应该返回一个int [],其中包含你应该种植花朵以实现上述目标的顺序的高度元素。 The front of the garden is represented by the first element in your return value, and is where you view the garden from. 花园的正面由您的返回值中的第一个元素表示,您可以从中查看花园。 The elements of height will all be unique, so there will always be a well-defined ordering. 高度元素都是独一无二的,因此总会有明确定义的顺序。

Edit two: 编辑二:

Example 1: 例1:

height={5,4,3,2,1} 高度= {5,4,3,2,1}

bloom={1,1,1,1,1} 开花= {1,1,1,1,1}

wilt={365,365,365,365,365} 萎= {365,365,365,365,365}

Returns: { 1, 2, 3, 4, 5 } 返回:{1,2,3,4,5}

These flowers all bloom on January 1st and wilt on December 31st. 这些花在1月1日开花,12月31日开花。 Since they all may block each other, you must order them from shortest to tallest. 由于它们都可能相互阻挡,因此必须从最短到最高的顺序进行排序。

Example 2: 例2:

h={5,4,3,2,1} H = {5,4,3,2,1}

b={1,5,10,15,20} B = {1,5,10,15,20}

w={4,9,14,19,24} W = {4,9,14,19,24}

Returns: { 5, 4, 3, 2, 1 } The same set of flowers now bloom all at separate times. 返回:{5,4,3,2,1}同一组花现在在不同的时间开花。 Since they will never block each other, you can order them from tallest to shortest to get the tallest ones as far forward as possible. 由于它们永远不会相互阻挡,因此您可以从最高到最短的顺序进行订购,以便尽可能地向前推进最高速度。

Example 3: height={5,4,3,2,1} 例3:height = {5,4,3,2,1}

bloom={1,5,10,15,20} 开花= {1,5,10,15,20}

wilt={5,10,14,20,25} 萎= {5,10,14,20,25}

Returns: { 3, 4, 5, 1, 2 } The difference here is that the third type of flower wilts one day earlier than the blooming of the fourth flower. 返回:{3,4,5,1,2}这里的区别在于第三种花比第四朵花开花早一天。 Therefore, we can put the flowers of height 3 first, then the flowers of height 4, then height 5, and finally the flowers of height 1 and 2. Note that we could have also ordered them with height 1 first, but this does not result in the maximum possible height being first in the garden. 因此,我们可以首先放置高度为3的花,然后是高度为4的花,然后是高度为5的花,最后是高度为1和2的花。请注意,我们也可以先将它们命令为高度1,但这不是导致最大可能的高度首先在花园里。

It's not a dynamic programming problem. 这不是一个动态的编程问题。 It's a greedy algorithm problem. 这是一个贪婪的算法问题。

This confused me too, since topcoder's own dynamic programming tutorial links to it as a practice problem in the “Elementary” section. 这也使我感到困惑,因为topcoder自己的动态编程教程将其作为“基本”部分中的练习题链接到它。

Sort the flowers by height, shortest to tallest. 按高度对花进行排序,最短到最高。 Start with an empty list of rows. 从一个空的行列表开始。 For each flower (shortest to tallest), find the forward-most place where you can insert that flower such that it blocks no flowers behind it. 对于每朵花(最短到最高),找到最前面的地方,你可以插入那朵花,使其不会阻挡它后面的花朵。

In Python: 在Python中:

def getOrdering(height, bloom, wilt):
    flowers = zip(height, bloom, wilt)
    flowers.sort()

    def flowersOverlap(f1, f2):
        # Overlap if each blooms before the other wilts.
        return f2[1] <= f1[2] and f1[1] <= f2[2]

    rows = [ ]
    for flower in flowers:
        rowIndex = len(rows)
        # Start at the back and march forward as long as
        # `flower` wouldn't block any flowers behind it.
        while rowIndex > 0 and not flowersOverlap(flower, rows[rowIndex - 1]):
            rowIndex -= 1
        rows[rowIndex:rowIndex] = [flower]

    return [flower[0] for flower in rows]
public int[] getOrdering(int[] height, int[] bloom, int[] wilt) {
    int[] optimal = new int[height.length];
    int[] optimalBloom = new int[bloom.length];
    int[] optimalWilt = new int[wilt.length];

    // init state
    optimal[0] = height[0];
    optimalBloom[0] = bloom[0];
    optimalWilt[0] = wilt[0];

    // run dynamic programming
    for(int i = 1; i < height.length; i ++) {
        int currHeight = height[i];
        int currBloom = bloom[i];
        int currWilt = wilt[i];

        int offset = 0; // by default, type i is to be put to 1st row
        for(int j = 0; j < i; j ++) {
            if(currWilt >= optimalBloom[j] && currWilt <= optimalWilt[j] ||
                    currBloom >= optimalBloom[j] && currBloom <= optimalWilt[j] ||
                    currWilt >= optimalWilt[j] && currBloom <= optimalBloom[j]) {  // life period overlap
                if(currHeight < optimal[j]) {  // life overlap, and type i is shorter than type j
                    offset = j;
                    break;
                } else {
                    offset = j + 1; // type i overlap with type j, and i is taller than j. Put i after j
                }
            } else {  // not overlap with current
                if(currHeight < optimal[j]) {
                    offset = j + 1; // type i not overlap with j, i is shorter than j, put i after j
                }
                // else keep offset as is considering offset is smaller than j
            }
        }

        // shift the types after offset
        for(int k = i - 1; k >= offset; k -- ) {
            optimal[k+1] = optimal[k];
            optimalBloom[k+1] = optimalBloom[k];
            optimalWilt[k+1] = optimalWilt[k];
        }
        // update optimal
        optimal[offset] = currHeight;
        optimalBloom[offset] = currBloom;
        optimalWilt[offset] = currWilt;
    }
    return optimal;
}

This is my tested working code. 这是我测试过的工作代码。

I'have been struggling with this exact question for a whole day, and also, i couldn't find any DP solution to it. 我一直在努力解决这个问题一整天,而且,我找不到任何DP解决方案。

Here is my greedy approach in java, similar to others already posted, the key point is to proceed under a height ordering. 这是我在java中的贪婪方法,类似于已经发布的其他方法,关键点是在高度排序下进行。 The reason is to avoid dealing with intermediate heights (referring to the already computed), given that a intermediate height can change the relative order of the previously computed ones . 原因是避免处理中间高度(参考已经计算过的),假设中间高度可以改变先前计算的高度的相对顺序

int[] height = new int[]{5, 3, 4};
int[] start =  new int[]{1, 3, 1};
int[] end =    new int[]{2, 4, 4};
System.out.println(Arrays.toString(new FlowerGarden().getOrdering(height, start, end)));

This is the only optimal substructure I could find. 这是我能找到的唯一最佳子结构。 But given that there is no overlapping among subproblems, this algorithm should not be considered DP but greedy. 但鉴于子问题之间没有重叠,这个算法不应该被视为DP而是贪婪。

private static boolean intersects(final int[] starts, final int[] ends, int i1, int i2) {
    return !(ends[i1] < starts[i2] || ends[i2] < starts[i1]);
}

public int[] getOrdering(final int[] height, final int[] starts, final int[] ends) {

    PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
        public int compare(Integer i, Integer j) {
            return Integer.compare(height[i], height[j]);
        }
    }
    );
    for (int i = 0; i < height.length; i++) {
        minHeap.add(i);
    }
    LinkedList<Integer> list = new LinkedList<Integer>();
    while (minHeap.size() > 0) {
        Integer index = minHeap.poll();
        int p = 1;
        int pos = 0;
        for (Integer i : list) {
            if (intersects(starts, ends, i, index)) {
                pos = p;
            }
            p++;
        }
        list.add(pos, index);
    }
    int[] ret = new int[height.length];
    int j = 0;
    for (Integer i : list) {
        ret[j++] = height[i];
    }
    return ret;
}

BTW, the DP solutions I have seen posted here fail for this example. 顺便说一句,我在这里发布的DP解决方案在这个例子中失败了。

Cheers 干杯

I tried to solve this problem too. 我也试图解决这个问题。 The main idea of my approach is to build a tree where each child is overlaped at least once by its parent. 我的方法的主要思想是建立一个树,其中每个孩子的父母至少重叠一次。

For example, if we have three flower types of heigths 4,2 and 1 growing and dying on the same days, then, the resulting tree should be: 例如,如果我们在同一天有三种花型4,2和1种生长和死亡,那么,生成的树应该是:

所有节点重叠

On the other hand, if 4 and 2 and 4 and 1 live at the same time but 2 and 1 do not coexist then, the resulting tree should be: 另一方面,如果4和2以及4和1同时存在,但是2和1不共存,则生成的树应该是:

两兄弟

That will generate a tree which is consistent with the problem contraints. 这将生成一个与问题约束一致的树。 Nonetheless the problem statement also includes a cost function making some solutions better than others. 尽管如此,问题陈述还包括成本函数,使得某些解决方案比其他解决方案更好。

...you also want to have the flowers in rows which are more towards the front be as tall as possible. ...你也希望将更多朝向前方的花朵尽可能地高。

The way to project this preference into our tree is to order all "brothers" (all nodes sharing the same parent) from higher to lower. 将此首选项投影到我们的树中的方法是将所有“兄弟”(所有节点共享同一父节点)从高到低排序。 So 2 comes first than 1. 所以2先到1。

I built this tree using the following code: 我使用以下代码构建了这个树:

#define INT_MOD(a,b) ((a<0)?(b+(a%b)):(a%b))
#define DIST(a,b) ((a-b>=0)?(a-b):(b-a))

//Prev: ForAll(i), bloom[i] < wilt[i]
inline bool isOverlap(vector<int> & bloom,
                      vector<int> & wilt,
                      vector<int> & height,
                      unsigned int idxPrev, unsigned int idxFollowing)
{
    int f1A = bloom[idxPrev];
    int f1B = wilt[idxPrev];
    int f2A = bloom[idxFollowing];
    int f2B = wilt[idxFollowing];

    bool notIntersecting = 
    f2A > f1B /* --[--]-(--)-- */ ||
    f1A > f2B /* --(--)-[--]-- */ ;

    return height[idxPrev] > height[idxFollowing] && !notIntersecting;
}


class CPreference {
public:
    static vector<int> * pHeight;
    static bool preference(int a, int b)
    {
        return (*pHeight)[a] > (*pHeight)[b];
    }
};
vector<int> * CPreference::pHeight = NULL;

vector<int> getOrdering(vector<int> height,
                        vector<int> bloom,
                        vector<int>  wilt)
{
    int l = height.size();
    vector<int> state = vector<int>(l, -1); /*  Tree where each leave points to its
                                                parent. Being that parent the first
                                                flower type that is forced to be
                                                after (backwards) its children */

    //This loop is the dynamic programming core.
    for(int i = 0; i < l; i++)
        for(int j = INT_MOD((i-1),l); j != i; j = INT_MOD((j-1),l))
        {
            if(isOverlap(bloom, wilt, height, i, j) &&
                (state[j] < 0 || DIST(height[j],height[i]) < DIST(height[j], height[state[j]])))
            {
                state[j] = i;
            }
        }

    vector<vector<int> > groups; //Groups of indexes overlapped by the element at the same index
    for(int i = 0; i < l+1; i++)
        groups.push_back(vector<int>()); // (l+1) for no overlapped indexes group.

    for(int i = 0; i < l; i++)
    {
        int k = state[i];
  if(k < 0) k = l;
  groups[k].push_back(i);
}

CPreference::pHeight = &height;
for(vector<vector<int> >::iterator it = groups.begin(); it != groups.end(); it++)
    sort(it->begin(),it->end(), CPreference::preference);

At this point, Each row (i) of groups contains, ordered from higher to lower, all flower types indexes that should be placed before the flower type of index i . 在这一点上, 群体中的每一行(I)含有,从较高的有序降低,应该花型指数的前放置鲜花的所有类型的索引。

One last step is needed, to flatten groups into an output vector. 需要最后一步,将展平为输出向量。 That is, to build a vector where each element is followed by either: 也就是说,构建一个向量,其中每个元素后跟:

  • Its parent on the tree. 它的父母在树上。
  • It next brother when sorted by height. 它的下一个兄弟按高度排序。

That can be done by a depth visit of each node of group . 这可以通过对的每个节点进行深度访问来完成。 I think that is the weak point of my solution. 我认为这是我的解决方案的弱点。 I had not so much time so I just made a naive recursive implementation: 我没有那么多时间所以我只是做了一个天真的递归实现:

//PRE: each vector, v, in 'groups' is sorted using CPreference
void flattenTree(vector<vector<int> > & groups, vector<int> & out, int currentIdx /*parent*/, int l)
{
    int pIdx = currentIdx;
    if(pIdx < 0) pIdx = l;

    vector<int> & elements = groups[pIdx];
    vector<int> ret;

    for(vector<int>::iterator it = elements.begin(); it != elements.end(); it++)
    {
        flattenTree(groups, out ,*it, l);
    }

    if(currentIdx>=0)
        out.push_back(currentIdx);
}

Which is used to completed getOrdering function: 用于完成getOrdering函数:

vector<int> getOrdering(vector<int> height,
            vector<int> bloom,
            vector<int>  wilt)
{
  int l = height.size();
  vector<int> state = vector<int>(l, -1); /* Tree where each leave points to its
                         parent. Being that parent the first
                         flower type that is forced to be
                         after (backwards) its children */
  for(int i = 0; i < l; i++)
    for(int j = INT_MOD((i-1),l); j != i; j = INT_MOD((j-1),l))
      {
        if(isOverlap(bloom, wilt, height, i, j) &&
        (state[j] < 0 || DIST(height[j],height[i]) < DIST(height[j], height[state[j]])))
        {
            state[j] = i;
        }
      }

  vector<vector<int> > groups; //Groups of indexes overlapped by the element at the same index
  for(int i = 0; i < l+1; i++)
    groups.push_back(vector<int>()); // (l+1) for no overlapped indexes group.

  for(int i = 0; i < l; i++)
    {
      int k = state[i];
      if(k < 0) k = l;
      groups[k].push_back(i);
    }

  CPreference::pHeight = &height;
  for(vector<vector<int> >::iterator it = groups.begin();
      it != groups.end(); it++)
    sort(it->begin(),it->end(), CPreference::preference);

   vector<int> ret;
   flattenTree(groups, ret, -1, l);
   for(unsigned int i = 0; i < ret.size(); i++)
    ret[i] = height[ret[i]];
    return ret; 
}

Please, let my know if you found a better solution or if know any way to improve mine. 如果您找到了更好的解决方案,或者知道如何改进我的解决方案,请告诉我。

package topcoders;

import java.util.ArrayList;
import java.util.List;

public class FlowerGarden {

    public int[] getOrdering(int[] height, int[] bloom, int[] wilt) {
        int[] order = new int[height.length];
        List<Integer> heightList = new ArrayList<Integer>();
        for (int i = 0; i < height.length; i++) {
            heightList.add(height[i]);
        }
        heightList = quickSort(heightList);
        for (int i = 0; i < height.length; i++) {
            height[i] = heightList.get(i);
        }
        order = height;
        for (int i = 0; i < order.length; i++) {
            int j = 0;
            while (j < order.length - 1
                    && isBlocking(j + 1, j, order, bloom, wilt)) {
                int placeHolder = order[j];
                order[j] = order[j + 1];
                order[j + 1] = placeHolder;
                j++;
            }
        }

        return order;
    }

    public boolean isBlocking(int isBlocked, int isBlocking, int[] order,
            int[] bloom, int[] wilt) {
        if (order[isBlocking] > order[isBlocked]
                && bloom[isBlocked] <= wilt[isBlocking]
                && wilt[isBlocked] >= bloom[isBlocking]) {
            return true;
        } else {
            return false;
        }
    }

    public List<Integer> quickSort(List<Integer> array) {
        if (array.size() <= 1) {
            return array;
        }
        int pivotIndex = array.size() / 2;
        int pivot = array.get(pivotIndex);
        List<Integer> less = new ArrayList<Integer>();
        List<Integer> greater = new ArrayList<Integer>();
        int l = 0;
        int g = 0;
        for (int i = 0; i < array.size(); i++) {
            if (i == pivotIndex) {
                continue;
            } else if (array.get(i) >= pivot) {
                less.add(array.get(i));
            } else {
                greater.add(array.get(i));
            }
        }
        List<Integer> lessResult = quickSort(less);


        List<Integer> greaterResult = quickSort(greater);

        List<Integer> result = new ArrayList<Integer>();
        result.addAll(lessResult);
        result.add(pivot);
        result.addAll(greaterResult);



        return result;
    }

    public static void main(String[] args) {
        int[] height = { 5, 4, 3, 2, 1 };
        int[] bloom = { 1, 5, 10, 15, 20 };
        int[] wilt = { 5, 10, 14, 20, 25 };
        FlowerGarden g = new FlowerGarden();
        List<Integer> arrayList = new ArrayList<Integer>();
        int[] array = g.getOrdering(height, bloom, wilt);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

A toplogical sort approach: 一种拓扑排序方法:

#include<stdio.h>
#include<stdlib.h>
#include <vector>  
#include <queue>  

using namespace std;

#define MAX_FLOWERS 50

struct flower
{
   int id;
   int height;
   int bloom;
   int wilt;
   bool visited;
   int ind;
};

struct flower_comp
{
  bool operator()(const struct flower* lhs, const struct flower* rhs) const
  {
    return rhs->height > lhs->height;
  }   
};

inline bool overlap(const struct flower& a, const struct flower& b)
{
    return !((a.bloom < b.bloom && a.wilt < b.bloom) || (a.bloom > b.bloom && a.bloom > b.wilt));
}

void getOrdering(int height[], int bloom[], int wilt[], int size)
{
    struct flower flowers[MAX_FLOWERS];

    for(int i = 0; i < size; i++)
    {
        flowers[i].id = i;
        flowers[i].height = height[i];
        flowers[i].bloom = bloom[i];
        flowers[i].wilt = wilt[i];
        flowers[i].visited = false;
        flowers[i].ind = 0;
    } 

    bool partial_order[MAX_FLOWERS][MAX_FLOWERS] = {false};

    for(int i = 0; i < size; i++)
    {
        for(int j = i + 1; j < size; j++)
        {
            if(overlap(flowers[i], flowers[j]))
            { 
               if(flowers[i].height < flowers[j].height)
               {
                  partial_order[i][j] = true;
                  flowers[j].ind++; 
               }
               else
               {
                  partial_order[j][i] = true;
                  flowers[i].ind++; 
               }
            }
        }
    }

    priority_queue<struct flower*, vector<struct flower*>, flower_comp> pq;

    for(int i = 0; i < size; i++)
    {
        if(flowers[i].ind == 0)
        {
           pq.push(&flowers[i]);
        }
    }

    printf("{");
    bool first = true;
    while(!pq.empty())
    {
        struct flower* tmp = pq.top();
        pq.pop(); 
        tmp->visited = true;
        if(!first)
        {
           printf(",");
        }
        first = false;
        printf("%d", tmp->height);
        for(int j = 0; j < size; j++)
        {
            if(!flowers[j].visited && partial_order[tmp->id][j])
            {
               flowers[j].ind--;
               if(flowers[j].ind == 0)
               {
                  pq.push(&flowers[j]);
               }
            }
        }
    }
    printf("}\n");
}

int main(int argc, char** argv)
{
    int height[] = {5,4,3,2,1};
    int bloom[] = {1,1,1,1,1};
    int wilt[] = {365,365,365,365,365};

    getOrdering(height, bloom, wilt, sizeof(height)/sizeof(height[0]));

    int height0[] = {5,4,3,2,1};
    int bloom0[] = {1,5,10,15,20};
    int wilt0[] = {4,9,14,19,24};

    getOrdering(height0, bloom0, wilt0, sizeof(height0)/sizeof(height0[0]));

    int height1[] = {5,4,3,2,1};
    int bloom1[] = {1,5,10,15,20};
    int wilt1[] = {5,10,15,20,25};

    getOrdering(height1, bloom1, wilt1, sizeof(height1)/sizeof(height1[0]));

    int height2[] = {5,4,3,2,1};
    int bloom2[] = {1,5,10,15,20};
    int wilt2[] = {5,10,14,20,25};

    getOrdering(height2, bloom2, wilt2, sizeof(height2)/sizeof(height2[0]));

    int height3[] = {1,2,3,4,5,6};
    int bloom3[] = {1,3,1,3,1,3};
    int wilt3[] = {2,4,2,4,2,4};

    getOrdering(height3, bloom3, wilt3, sizeof(height3)/sizeof(height3[0]));

    int height4[] = {3,2,5,4};
    int bloom4[] = {1,2,11,10};
    int wilt4[] = {4,3,12,13};

    getOrdering(height4, bloom4, wilt4, sizeof(height4)/sizeof(height4[0]));

}

Same thing as Rob's but in Javascript (ES6): 与Rob相同,但在Javascript(ES6)中:

function getOrdering(height, bloom, wilt) {
    var n = height.length;

    var idx = [];
    for (var i = 0; i < n; ++i) idx[i] = i;

    idx.sort( (a, b) => height[a] - height[b] );

    var intersect = (a, b) => !(bloom[a] > wilt[b] || bloom[b] > wilt[a]);

    for (var i = 1; i < n; ++i) {
        // assume they are ordered correctly till index (i-1),
        // start moving flower i to the left until it can't move because of intersection
        var j = i, flw = idx[i];
        while (j > 0 && !intersect(idx[j-1], flw)) {
            idx[j] = idx[j-1];
            idx[--j] = flw;
        }
    }

    return idx.map( x => height[x] );
}

Similar to Rob, again in Python and slightly convoluted overlapping bloom/wilt check. 类似于Rob,再次使用Python和稍微复杂的重叠bloom / wilt检查。

H = 0
B = 1
W = 2

def getOrdering(heights, blooms, wilts):

    def _f1_after_f2(f1, f2):
        fs1 = set(range(f1[B], f1[W]+1))
        fs2 = set(range(f2[B], f2[W]+1))
        return f1[H] > f2[H] if fs2.intersection(fs1) != set([]) else False

    fs = zip(heights, blooms, wilts)
    fs.sort()
    ffs = []
    for f1 in fs:
        insert_at = len(ffs)
        for f2 in reversed(ffs):
            if _f1_after_f2(f1, f2): break
            insert_at -= 1
        ffs.insert(insert_at, f1)
    return [f[H] for f in ffs]

A graph algorithm to solve the problem: 解决问题的图算法:

Create a directed graph(V,E): V -> flower types E -> relations between 2 flower types 创建有向图(V,E):V - >花型E - >两种花型之间的关系

For all pairs (v_i, v_j)
  If v_i is smaller than v_j and v_j 'blocks' v_i
    draw an edge starting from v_i to v_j
For all nodes v_i
  Find the v_i with no incoming edges and the biggest height
   -> write it at the end of the result list
   -> remove v_i and all of its outgoing edges from graph

For more description checkout this forum: Topcoder Forum - FlowerGarden 有关更多说明,请访问此论坛: Topcoder论坛 - FlowerGarden

Mine is like insertion sort. 我就像插入排序。 For each new flower, it goes from back to front and checks to see if the one in front of it blocks it; 对于每一朵新花,它从后到前检查,看它前面的那个是否阻挡它; if it does, it means it must be placed behind it. 如果是的话,就意味着它必须放在它后面。 Likewise, it also searches from front to back and checks to see if the one behind it blocks it; 同样,它也会从前到后进行搜索并检查后面的一个是否会阻止它; if it does, it means it must be placed in front of it. 如果是的话,这意味着它必须放在它的前面。 If there are no blocks, it simply checks for the best spot height-wise. 如果没有块,它只是检查最佳点高度。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>

#define uint32 uint32_t

static void
Swap(int *AIdx, int *BIdx)
{
    int Tmp = *AIdx;
    *AIdx = *BIdx;
    *BIdx = Tmp;
}

static void
SwapTo(int Start, int End, int *Array)
{
    while(Start != End)
    {
        Swap(&Array[Start], &Array[Start - 1]);
        --Start;
    }
}

static void
PrintTo(int End, int *Array)
{
    for(int Idx = 0;
        Idx < End;
        ++Idx)
    {
        printf("%d, ", Array[Idx]);
    }
    printf("\n");
}

/* Does A block B? */
static bool
Blocks(int AIdx, int BIdx, int *Heights, int *Blooms, int *Wilts)
{
    bool Result = (Heights[AIdx] > Heights[BIdx] &&
                   Wilts[AIdx] >= Blooms[BIdx] && 
                   Blooms[AIdx] <= Wilts[BIdx]);

    return Result;
}

static void
Order(int *Heights, int *Blooms, int *Wilts, 
      int FlowerCount)
{
    for(int FlowerIdx = 1;
        FlowerIdx < FlowerCount;
        ++FlowerIdx)
    {
        PrintTo(FlowerIdx, Heights);

        /* front to back */
        int MinIdx = -1;
        for(int Idx = 0;
            Idx < FlowerIdx;
            ++Idx)
        {
            if(Blocks(Idx, FlowerIdx, Heights, Blooms, Wilts))
            {
                MinIdx = Idx;
                break;
            }
        }

        /* back to front */
        int MaxIdx = -1;
        for(int Idx = (FlowerIdx - 1);
            Idx >= 0;
            --Idx)
        {
            if(Blocks(FlowerIdx, Idx, Heights, Blooms, Wilts))
            {
                MaxIdx = (Idx + 1);
                break;
            }
        }

        /* best height index */
        int BestHeightIdx = -1;
        if(MinIdx == -1 &&
           MaxIdx == -1)
        {
            for(int Idx = 0;
                Idx < FlowerIdx;
                ++Idx)
            {
                if(Heights[FlowerIdx] > Heights[Idx])
                {
                    BestHeightIdx = Idx;
                    break;
                }
            }

            if(BestHeightIdx == -1)
            {
                BestHeightIdx = FlowerIdx;
            }
        }

        int SwapToIdx = -1;
        if((MaxIdx == -1 && MinIdx != -1) ||
           (MinIdx == -1 && MaxIdx != -1) ||
           (MaxIdx != -1 && MinIdx != -1 && MaxIdx == MinIdx))
        {
            SwapToIdx = (MinIdx != -1) ? MinIdx : MaxIdx;
        }
        else if(BestHeightIdx != -1)
        {
            SwapToIdx = BestHeightIdx;
        }
        else
        {
            fprintf(stderr, "Spot-finding error:\n MinIdx: %d, MaxIdx: %d, BestHIdx: %d\n",
                    MinIdx, MaxIdx, BestHeightIdx);
            exit(1);
        }

        SwapTo(FlowerIdx, SwapToIdx, Heights);
        SwapTo(FlowerIdx, SwapToIdx, Blooms);
        SwapTo(FlowerIdx, SwapToIdx, Wilts);
    }
}

int
main(int argc, char *argv[])
{
    int Heights0[]  = {5,4,3,2,1};
    int Blooms0[]   = {1,1,1,1,1};
    int Wilts0[]    = {365,365,365,365,365};

    int Heights1[]  = {5,4,3,2,1};
    int Blooms1[]   = {1,5,10,15,20};
    int Wilts1[]    = {4,9,14,19,24};

    int Heights2[]  = {5,4,3,2,1};
    int Blooms2[]   = {1,5,10,15,20};
    int Wilts2[]    = {5,10,15,20,25};

    int Heights3[]  = {5,4,3,2,1};
    int Blooms3[]   = {1,5,10,15,20};
    int Wilts3[]    = {5,10,14,20,25};

    int Heights4[]  = {1,2,3,4,5,6};
    int Blooms4[]   = {1,3,1,3,1,3};
    int Wilts4[]    = {2,4,2,4,2,4};

    int Heights5[]  = {3,2,5,4};
    int Blooms5[]   = {1,2,11,10};
    int Wilts5[]    = {4,3,12,13};

    int *AllHeights[] = {Heights0, Heights1, Heights2, Heights3, Heights4, Heights5};
    int *AllBlooms[] = {Blooms0, Blooms1, Blooms2, Blooms3, Blooms4, Blooms5};
    int *AllWilts[] = {Wilts0, Wilts1, Wilts2, Wilts3, Wilts4, Wilts5};
    int AllFlowerCounts[] = {5, 5, 5, 5, 6, 4};

    printf("\n");
    for(int Idx = 0;
        Idx < 6;
        ++Idx)
    {
        int *Heights = AllHeights[Idx];
        int *Blooms = AllBlooms[Idx];
        int *Wilts = AllWilts[Idx];
        int FlowerCount = AllFlowerCounts[Idx];

        printf("Test %d\n", Idx);
        Order(Heights, Blooms, Wilts, FlowerCount);
        printf("{ ");
        for(int Idx = 0;
            Idx < FlowerCount;
            ++Idx)
        {
            printf("%d", Heights[Idx]);
            if(Idx != (FlowerCount - 1))
            {
                printf(", ");
            }
        }
        printf(" }\n\n");
    }
}

EDIT: This solution is god awful and I came up with a better one that's actually DP; 编辑:这个解决方案太糟糕了,我想出了一个更好的DP,实际上是DP; it's as follows: for each flower, loop through all other flowers checking which ones it blocks; 它如下:对于每朵花,环绕所有其他花朵,检查它阻挡哪些; for those flowers it blocks, check for all the flowers it blocks, and so on until you get to a flower that doesn't block any other ones. 对于它阻挡的那些花,检查它阻挡的所有花,等等,直到你得到一朵不会阻挡任何其他花的花。 Put that flower in a new array. 把那朵花放在一个新的阵列中。 Backtrack and put each flower before it in the next slot of that new array. 回溯并将每朵花放在新阵列的下一个插槽中。 If done for each flower, you will get an array full of flowers that don't block any others. 如果为每朵花做完,你会得到一个充满鲜花的阵列,不会阻挡任何其他花朵。 You then put each flower as far forward as possible. 然后你将每朵花尽可能向前放。 The DP part of this solution is that sometimes you'll come across the same flower that has already been blocked by another flower previously and has already been put in the new array, so we skip that flower instead of chasing down the flowers it blocks. 这个解决方案的DP部分是,有时你会遇到已经被另一朵花阻挡的同一朵花,并且已经被放入新的阵列中,所以我们跳过那朵花而不是追逐它所阻挡的花朵。

I have got the implementation in c++. 我已经用c ++实现了。 I have used a vector datatype to store the height, bloom and wilt respectively and then i sorted it wrt to height after which i took the flowers one by one and arranged them according to the values associated with them. 我已经使用了一个矢量数据类型来分别存储高度,绽放和枯萎,然后我将它分类到高度,之后我逐一取花并根据与它们相关的值进行排列。

here is the code :- 这是代码: -

#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std;

bool comp(pair<int, pair<int,int> >& a,pair<int, pair<int,int> >& b ){
    return (a.first > b.first);
}




bool justify(pair<int, pair<int,int> >& a,pair<int, pair<int,int> >& b, int k , int 
j,  vector<pair<int,pair<int,int> > >& v){
    if(((b.second.first <= a.second.first) && (b.second.second>= a.second.first)) || 
    ((b.second.first <= a.second.second) && (b.second.second>= a.second.second)) || 
    ((b.second.first > a.second.first) && (b.second.second < a.second.second) )){

            pair<int, pair<int,int> > temp = v[j];     
          int i = j-1;
       while(i >= k){

          v[i+1] = v[i];
          i--;


        }
        v[k] = temp;
        return true;
  }
  return false;
}




int main() {

  vector<pair<int,pair<int,int> > > v;
  int n,a,b,c;
  cin>>n;
  for(int i = 0;i < n;i++){
    cin>>a>>b>>c;
    v.push_back(make_pair(a,make_pair(b,c)));
 }


sort(v.begin(), v.end(), comp);



for(int j = 1;j < n;j++){
  for(int k = 0;k < j;k++){
    bool res = justify(v[k],v[j], k, j, v);
   if(res)
   break;
  }
 }

cout<<"output"<<endl;
for(int i = 0;i < n;i++){
    cout<<v[i].first<<" "<<v[i].second.first<<" "<<v[i].second.second<<endl;
}
return 0;

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM