There is an interesting game named one person game. It is played on a m*n grid. There is an non-negative integer in each grid cell. You start with a score of 0. You cannot enter a cell with an integer 0 in it. You can start and end the game at any cell you want (of course the number in the cell cannot be 0). At each step you can go up, down, left and right to the adjacent grid cell. The score you can get at last is the sum of the numbers on your path. But you can enter each cell at most once.
The aim of the game is to get your score as high as possible.
Input:
The first line of input is an integer T the number of test cases. The first line of each test case is a single line containing 2 integers m and n which is the number of rows and columns in the grid. Each of next the m lines contains n space-separated integers D indicating the number in the corresponding cell
Output:
For each test case output an integer in a single line which is maximum score you can get at last.
Constraints:
T is less than 7.
D is less than 60001.
m and n are less than 8.
Sample Input:
4
1 1
5911
1 2
10832 0
1 1
0
4 1
0
8955
0
11493
Sample Output:
5911
10832
0
11493
I tried it but my approach is working very slow for a 7x7 grid.I am trying to access every possible path of the grid recursively and comparing the sum of every path.Below is my code
#include<iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
int max(int a,int b,int c, int d)
{
int max = a;
if(b>max)
max = b;
if(c>max)
max = c;
if(d>max)
max = d;
return max;
}
int Visit_Component( int (*A)[8], int Visit[8][8], int m,int n , int row, int col)
{
if ( ( row >= m ) || (col >= n ) || (col < 0) || (row < 0) || A[row][col] == 0 || Visit[row][col] == 1 )
{
return 0;
}
else
{
Visit[row][col] = 1;
int a= 0,b=0,c=0,d=0,result =0;
a = Visit_Component( A, Visit,m,n, row+1, col);
b = Visit_Component( A, Visit,m,n, row, col +1);
c = Visit_Component( A, Visit,m,n, row, col -1);
d = Visit_Component( A, Visit,m,n, row-1, col );
Visit[row][col] = 0;
result = A[row][col] + max(a,b,c,d);
return result;
}
}
int main(){
int T;
scanf("%d",&T);
for(int k =0; k<T;k++)
{
int N ;
int M;
int count = 0;
int maxcount = 0;
scanf("%d %d",&M,&N);
int C[8][8];
int visit[8][8];
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
{
scanf("%d",&C[i][j]);
visit[i][j] = 0;
}
for( int i= 0 ; i< M ; i++ )
{
for( int j =0; j< N ; j++ )
{
count = Visit_Component( C, visit,M,N, i, j);
if(count > maxcount)
{
maxcount = count;
}
}
}
printf("%d\n",maxcount);
}
return 0;
}
Please suggest me how to optimize this approach or a better algorithm.
As Wikipedia article on Travelling salesman problem suggests, there are exact algorithms, solving this task quickly. But it is hard to find any. And they are, most likely, complicated.
As for optimizing OP's approach, there are several possibilities.
It's easier to start with simple micro-optimization: condition Visit[row][col] == 1 is satisfied with highest probability, so it should come first.
Also it is reasonable to optimize branch-and-bound algorithm with dynamic programming to avoid some repeated calculations. Memorizing calculation results in simple hash table for the cases of up to 19 visited cells improves performance by more than 25% (and more may be expected for some improved hash table). Here is the modified code snippet:
#include<iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
int max(int a,int b,int c, int d)
{
int max = a;
if(b>max)
max = b;
if(c>max)
max = c;
if(d>max)
max = d;
return max;
}
typedef unsigned long long ull;
static const int HS = 10000019;
static const int HL = 20;
struct HT {
ull v;
int r;
int c;
};
HT ht[HS] = {0};
int Visit_Component(
int (*A)[8], ull& Visit, int m,int n , int row, int col, int x)
{
if ( (Visit & (1ull << (8*row+col))) || ( row >= m ) || (col >= n ) ||
(col < 0) || (row < 0) || A[row][col] == 0)
{
return 0;
}
else
{
if (x < HL)
{
HT& h = ht[(Visit+4*row+col)%HS];
if (h.v == Visit && h.r == row && h.c == col)
return 0;
}
Visit |= (1ull << (8*row+col));
int a= 0,b=0,c=0,d=0,result =0;
a = Visit_Component( A, Visit,m,n, row+1, col, x+1);
b = Visit_Component( A, Visit,m,n, row, col +1, x+1);
c = Visit_Component( A, Visit,m,n, row, col -1, x+1);
d = Visit_Component( A, Visit,m,n, row-1, col , x+1);
Visit &= ~(1ull << (8*row+col));
result = A[row][col] + max(a,b,c,d);
if (x < HL)
{
HT& h = ht[(Visit+4*row+col)%HS];
h.v = Visit;
h.r = row;
h.c = col;
}
return result;
}
}
int main(){
int T;
scanf("%d",&T);
for(int k =0; k<T;k++)
{
int N ;
int M;
int count = 0;
int maxcount = 0;
scanf("%d %d",&M,&N);
int C[8][8];
ull visit = 0;
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
{
scanf("%d",&C[i][j]);
}
for( int i= 0 ; i< M ; i++ )
{
for( int j =0; j< N ; j++ )
{
count = Visit_Component( C, visit,M,N, i, j, 0);
if(count > maxcount)
{
maxcount = count;
}
}
}
printf("%d\n",maxcount);
}
return 0;
}
And much more improvements may be done by pre-processing the input matrix. If there are no zeros in the matrix or if there is only one zero in the corner, you may just sum all the values.
If there is only one zero value (not in the corner), at most one non-zero value should be excluded from the sum. If you invent an algorithm, that determines the subset of cells, from which one of the cells must be removed, you can just select the smallest value from this subset.
If there are two or more zero values, use branch-and-bound algorithm: in this case it is about 20 times faster, because each zero value in input matrix means approximately fivefold speed increase.
One optimization that I can think of is to apply Dijkstra's algorithm. This algorithm will give you a minimum (in your case maximum) path for a particular source node to all destination nodes.
In this example, the first step would be to build a graph.
And because you don't know the source node to start at, you will have to apply Dijkstra's algorithm for each node in the grid. The time complexity will be better than your recursion method because for a particular source node, when finding a maximum path Dijkstra's algorithm does not go through all the possible paths.
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int> >A;
vector<vector<bool> >test;
vector<vector<bool> >test1;
int sum_max=0;
int m,n;
vector<vector<bool> > stamp;
void color1(int i,int j,vector<vector<bool> >temp_vector,vector<vector<bool> > st,int summ){
temp_vector[i][j]=false;summ+=A[i][j];st[i][j]=true;
//1.1
if(i+1<m && temp_vector[i+1][j]){
if(test1[i+1][j]){
if(sum_max<(summ)){sum_max=summ;stamp=st;}
}
else{color1(i+1,j,temp_vector,st,summ);}
}
//1.2
if(i+1<m){if(!temp_vector[i+1][j]){ if(sum_max<(summ)){sum_max=summ;}}}
if(i+1>=m){if(sum_max<(summ)){sum_max=summ;}}
//2
if(i-1>=0 && temp_vector[i-1][j]){
if(test1[i-1][j]){
if(sum_max<(summ)){sum_max=summ;}
}
else{ color1(i-1,j,temp_vector,st,summ);}
}
//2.2
if(i-1>=0){if(!temp_vector[i-1][j]){ if(sum_max<(summ)){sum_max=summ;}}}
if(i-1<0){if(sum_max<(summ)){sum_max=summ;}}
//3
if(j+1<n && temp_vector[i][j+1]){
if(test1[i][j+1]){
if(sum_max<(summ)){sum_max=summ;}
}
else{ color1(i,j+1,temp_vector,st,summ);}}
//3.2
if(j+1<n){if(!temp_vector[i][j+1]){ if(sum_max<(summ)){sum_max=summ;}}}
if(j+1>=n){if(sum_max<(summ)){sum_max=summ;}}
//4
if(j-1>=0 && temp_vector[i][j-1]){
if(test1[i][j-1]){
if(sum_max<(summ)){sum_max=summ;}
}
else{ color1(i,j-1,temp_vector,st,summ);}}
//4.2
if(j-1>=0){if(!temp_vector[i][j-1]){ if(sum_max<(summ)){sum_max=summ;}}}
if(j+1<0){if(sum_max<(summ)){sum_max=summ;}}
}
void color(int i,int j){
test[i][j]=false;
if(i+1<m && test[i+1][j]){
color(i+1,j);}
if(i-1>=0 && test[i-1][j]){
color(i-1,j);
}
if(j+1<n && test[i][j+1]){
color(i,j+1);}
if(j-1>=0 && test[i][j-1]){color(i,j-1);}
}
int main(){
int tc;cin>>tc;
for(int i=0;i<tc;i++){
int mp,np;
cin>>mp;
cin>>np;m=mp;n=np;A.resize(m);test.resize(m);test1.resize(m);int sum=0;
vector<bool> ha1(m,1);
vector<bool> ha2(n,1);
for(int i=0;i<m;i++){A[i].resize(n);test[i].resize(n);test1[i].resize(n);
for(int j=0;j<n;j++){
cin>>A[i][j];sum+=A[i][j];
test[i][j]=true;test1[i][j]=false;
if(A[i][j]==0){test[i][j]=false;ha1[i]=false;ha2[j]=false;}
}
}cout<<endl;
for(int i=0;i<m;i++){cout<<" "<<ha1[i];} cout<<endl;
for(int i=0;i<n;i++){cout<<" "<<ha2[i];} cout<<endl;
cout<<"sum "<<sum<<"\n";
int temp_sum=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){//if(A[i][j]<=8845){cout<<"\nk "<<A[i][j]<<" "<<(8845-A[i][j]);}
if(test[i][j]){
if((i-1)>=0 && test[i-1][j] && (i+1)<m && test[i+1][j] && (j-1)>=0 && test[i][j-1] && (j+1)<n && test[i][j+1] && test[i-1][j-1] && test[i-1][j+1]&& test[i+1][j-1] && test[i+1][j+1]){
temp_sum+=A[i][j];test1[i][j]=true;}
}
// cout<<test1[i][j]<<" ";
}//cout<<"\n";
}
// /*
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(test1[i][j]){if(!((test1[i-1][j]||test1[i+1][j]) && (test1[i][j-1]||test1[i][j+1]))){
temp_sum-=A[i][j]; test1[i][j]=false;}
}
//
// cout<<test1[i][j]<<" ";
}//
// cout<<"\n";
}
// */
//cout<<"\n temp_sum is "<<temp_sum<<endl;
vector<vector<bool> > st(m,vector<bool>(n,0));st=test1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(test[i][j] && (!test1[i][j])){
color1(i,j,test,st,0);
}}}
// cout<<"\nsum is "<<(sum_max+temp_sum)<<endl<<endl;
cout<<(sum_max+temp_sum)<<endl;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){cout<<stamp[i][j]<<" ";} cout<<endl;}
// cout<<max<<endl;
A.clear();
test.clear();
test1.clear();
sum_max=0;
}
cout<<endl;system("pause");
return 0;
}
I'm reading this excellent tutorial by Dumitru on DP based problems here. And I'm trying to come up with a DP based approach for the FlowerGarden problem mentioned in the list of 1D DP problems.
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. That doesn't classify as DP, does it?
The editorial also doesn't mention anything about DP.
Could anyone, by any chance, point me to a proper DP-based solution to this problem?
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.
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]. 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. 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:
height={5,4,3,2,1}
bloom={1,1,1,1,1}
wilt={365,365,365,365,365}
Returns: { 1, 2, 3, 4, 5 }
These flowers all bloom on January 1st and wilt on December 31st. Since they all may block each other, you must order them from shortest to tallest.
Example 2:
h={5,4,3,2,1}
b={1,5,10,15,20}
w={4,9,14,19,24}
Returns: { 5, 4, 3, 2, 1 }
The same set of flowers now bloom all at separate times. 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}
bloom={1,5,10,15,20}
wilt={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. 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.
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.
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:
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.
Here is my greedy approach in java, similar to others already posted, the key point is to proceed under a height ordering. 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.
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.
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:
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:
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.
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.
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:
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):
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.
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
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
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; 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.
I have got the implementation in c++. I have used a vector datatype to store the height, bloom and wilt respectively and then i sorted it w.r.t 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;
}