Perfect Bin Packing solution algorithm - algorithm

Is there a way to solve a 1D bin-packing totally efficient, differtent from brute-force? And if it isn't, what is the best way to brute-force attack the problem? I've tried decreasing best fit, and decreasing first fit, but they both don't work totally efficient. The code i've made untill now is below: (Some functions are not shown, namely Sort and Swap, but suppose these work perfectly, they do!)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
void swap(int* x, int* y);
void sort(int values[], int n);
int choose(int fill[], int *fills, int val, int max);
int main(void){
int lw, cn;
// get first two numbers
scanf("%i", &lw);
scanf("%i", &cn);
//
int cw[cn], i, lf[1000], lc = 0, lp;
memset(lf, 0 , sizeof(lf));
// get width of all the clothes
for(i = 0; i < cn; i++){
scanf("%i", &cw[i]);
}
// sort cw
sort(cw, cn);
// apply bin packing - bestfit, sorted
for( i = 0; i < cn; i++){
lp = choose(lf, &lc, cw[i], lw);
lf[lp] += cw[i];
printf("lf[%i] += %i, maakt %i \n", lp , cw[i], lf[lp]);
}
// return nr of bins
printf("Uiteindelijke lc= %i\n", lc);
}
int choose(int fill[], int *fills, int val, int max){
int x, lessid, less = 0;
bool changed = 0;
for(x = 0; x <= *fills; x++){
/* best fit
if( ((fill[x] + val) < max) && ((fill[x] + val) > less)){
lessid = x;
less = fill[x];
changed = 1;
}
if (changed == 1) { return lessid;}
else {
*fills+=1;
return *fills;
}
}*/
//First fit
if( (fill[x] + val) < max) {
return x;
}
*fills+=1;
return *fills;
}
}

Branch and Bound is more efficient than Brute Force. But it's still an exhaustive search and it still hits the scalability wall.

Related

Generating random numbers into an array which prints to a Txt file. Before hitting the text file, the numbers need to be sorted

so my objective is to basically print out random numbers from 40,000 to 1,000,000 to a txt file, sorted using the heap method. I can print to the text file just fine with random numbers, but I am a bit stuck at sorting them using a heap method. I started a method and got a bit lost half way through after looking at some tutorials. Any thoughts/ helpful comments? Im literally new to stack overflow (posting wise) so forgive me if I didnt place this here correctly. Thank you!
//Heapsort algorithm
#include <iostream>
#include <string>
#include <fstream>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
/*class generateDataSet {
public: static const int MAX_VALUE = 1000000;
public: static const bool SORTED = false;
public: static const bool REVERSE_SORTED = false;
};
*/
int main()
{
const int array= 16;
int arrayNum[array];
srand(time(NULL));
int upB = 1000000;
int loB = 40000;
int temp;
ofstream inputFile;
inputFile.open("randomData.txt");
if (inputFile.is_open())
{
for (int i = 0; i < array; i++)
{
arrayNum[i] = (rand()% (upB - loB + 1)) + loB;
inputFile << arrayNum[i] << "\n";
}
}
return 0;
}
void MaxHeapify(int d[], int i, int n)
{
int j;
int temp;
temp = d[i];
j = 2 * 1;
while (j <= n)
{
if (j < n && d[j + 1] > d[j])
j = j + 1;
if (temp > d[j])
break;
else if (temp <= d[j])
{
d[j / 2] = d[j];
j = 2 * j;
}
}
}
void heapSort(int d[], int n)
{
int i;
int temp;
for (i = n; i >= 2; i);
}

How to improve Dijkstra algorithm when querying n times?

I'm currently working on a problem at Codechef. You can find the problem statement here:
Delivery Boy
In short, the problem is asking to query n times the shortest path from a start to an end. My solution is to use Dijsktra with priority_queue plus caching the result into a hash_map in case we already had a start. Unfortunately, I got time limit exceed many times and I couldn't find a better way to make it faster. I wonder am I in the right track? or there is a better algorithm to this problem?
By the way, since the contest is still going, please don't post any solution. A hint is more than enough to me. Thanks.
Here is my attempt:
#ifdef __GNUC__
#include <ext/hash_map>
#else
#include <hash_map>
#endif
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <utility>
#include <stack>
#include <deque>
#include <queue>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
using namespace std;
#ifdef __GNUC__
namespace std {
using namespace __gnu_cxx;
}
#endif
const int MAX_VERTICES = 250;
const int INFINIY = (1 << 28);
int weight[MAX_VERTICES + 1][MAX_VERTICES + 1];
bool visited_start[MAX_VERTICES + 1] = { 0 };
struct vertex {
int node;
int cost;
vertex(int node = 0, int cost = 0)
: node(node), cost(cost) {
}
bool operator <(const vertex& rhs) const {
return cost < rhs.cost;
}
bool operator >(const vertex& rhs) const {
return cost > rhs.cost;
}
};
hash_map<int, vector<vertex> > cache;
typedef priority_queue<vertex, vector<vertex>, greater<vertex> > min_pq;
vector<vertex> dijkstra_compute_path(int start, int n) {
min_pq pq;
vector<vertex> path;
vector<int> visited(n, 0);
int min_cost = 0;
int better_cost;
vertex u;
for (int i = 0; i < n; ++i) {
path.push_back(vertex(i, INFINIY));
}
path[start].cost = 0;
pq.push(vertex(start, path[start].cost));
while (!pq.empty()) {
// extract min cost
u = pq.top();
pq.pop();
// mark it as visited
visited[u.node] = 1;
// for each vertex v that is adjacent to u
for (int v = 0; v < n; ++v) {
// if it's not visited, visit it
if (visited[v] == 0) {
better_cost = path[u.node].cost + weight[u.node][v];
// update cost
if (path[v].cost > better_cost) {
path[v].cost = better_cost;
pq.push(vertex(v, path[v].cost));
}
}
}
}
return path;
}
void check_in_cache(vector<vertex>& path, int start, int no_street) {
if (visited_start[start] == 0) {
path = dijkstra_compute_path(start, no_street);
cache.insert(make_pair(start, path));
visited_start[start] = 1;
}
else {
path = cache[start];
}
}
void display_cost(int stop_at_gas_cost, int direct_cost) {
printf("%d ", stop_at_gas_cost);
if (stop_at_gas_cost > direct_cost) {
printf("%d\n", stop_at_gas_cost - direct_cost);
}
else {
printf("0\n");
}
}
void handle_case_one() {
int no_scenario;
int dummy;
int s, g, d;
scanf("%d", &dummy);
scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &s, &g, &d);
printf("0 0\n");
}
}
void inout_delivery_boy() {
int no_street;
int no_scenario;
int restaurant;
int gas_station;
int destination;
int stop_at_gas_cost;
int direct_cost;
vector<vertex> direct;
vector<vertex> indirect;
vector<vertex> d;
int c;
scanf("%d", &no_street);
if (no_street == 1) {
handle_case_one();
return;
}
for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
scanf("%d", &c);
weight[x][y] = c;
}
}
for (int i = 0; i < no_street; ++i) {
d.push_back(vertex(i, INFINIY));
}
scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &restaurant, &gas_station, &destination);
// check in cache
check_in_cache(direct, restaurant, no_street);
check_in_cache(indirect, gas_station, no_street);
// calculate the cost
stop_at_gas_cost = direct[gas_station].cost + indirect[destination].cost;
direct_cost = direct[destination].cost;
// output
display_cost(stop_at_gas_cost, direct_cost);
}
}
void dijkstra_test(istream& in) {
int start;
int no_street;
int temp[4] = { 0 };
vector<vertex> path;
in >> no_street;
for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
in >> weight[x][y];
}
}
// arrange
start = 0;
temp[0] = 0;
temp[1] = 2;
temp[2] = 1;
temp[3] = 3;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 1;
temp[0] = 1;
temp[1] = 0;
temp[2] = 2;
temp[3] = 4;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 2;
temp[0] = 2;
temp[1] = 1;
temp[2] = 0;
temp[3] = 3;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 3;
temp[0] = 1;
temp[1] = 1;
temp[2] = 1;
temp[3] = 0;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
}
int main() {
// ifstream inf("test_data.txt");
// dijkstra_test(inf);
inout_delivery_boy();
return 0;
}
please notice N is small in the problem. have you tried Floyd shortest path algorithm to pre-calculate shortest path between each two nodes ? it will cost O(N^3) time, which is 250^3=15625000 in the problem, should be easy to be finished running in 1 second. Then you can answer each query in O(1).
the introduction of Floyd :
http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
ps: i think cached dijstra costs a maximum running time of O(N^3) for overall test case as well . but the way you implement the cache will spend more unnecessary time on memory copying, which may lead to a TLE. Just a guess.
Indeed Floyd-Warshall's Algorithm is better than Dijkstra's in this case, the complexity for Dijkstra is O(m*n^2) and in this problem M is much much higher than N so the O(n^3) time complexity of Floyd-Warshall is better.

High score in grid walk

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;
}

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

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;
}

Find longest non-decreasing sequence

Given the following question,
Given an array of integers A of length n, find the longest sequence {i_1, ..., i_k} such that i_j < i_(j+1) and A[i_j] <= A[i_(j+1)] for any j in [1, k-1].
Here is my solution, is this correct?
max_start = 0; // store the final result
max_end = 0;
try_start = 0; // store the initial result
try_end = 0;
FOR i=0; i<(A.length-1); i++ DO
if A[i] <= A[i+1]
try_end = i+1; // satisfy the condition so move the ending point
else // now the condition is broken
if (try_end - try_start) > (max_end - max_start) // keep it if it is the maximum
max_end = try_end;
max_start = try_start;
endif
try_start = i+1; // reset the search
try_end = i+1;
endif
ENDFOR
// Checking the boundary conditions based on comments by Jason
if (try_end - try_start) > (max_end - max_start)
max_end = try_end;
max_start = try_start;
endif
Somehow, I don't think this is a correct solution but I cannot find a counter-example that disapprove this solution.
anyone can help?
Thank you
I don't see any backtracking in your algorithm, and it seems to be suited for contiguous blocks of non-decreasing numbers. If I understand correctly, for the following input:
1 2 3 4 10 5 6 7
your algorithm would return 1 2 3 4 10 instead of 1 2 3 4 5 6 7.
Try to find a solution using dynamic programming.
You're missing the case where the condition is not broken at its last iteration:
1, 3, 5, 2, 4, 6, 8, 10
You'll never promote try_start and try_end to max_start and max_end unless your condition is broken. You need to perform the same check at the end of the loop.
Well, it looks like you're finding the start and the end of the sequence, which may be correct but it wasn't what was asked. I'd start by reading http://en.wikipedia.org/wiki/Longest_increasing_subsequence - I believe this is the question that was asked and it's a fairly well-known problem. In general cannot be solved in linear time, and will also require some form of dynamic programming. (There's an easier n^2 variant of the algorithm on Wikipedia as well - just do a linear sweep instead of the binary search.)
#include <algorithm>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <assert.h>
template<class RandIter>
class CompM {
const RandIter X;
typedef typename std::iterator_traits<RandIter>::value_type value_type;
struct elem {
value_type c; // char type
explicit elem(value_type c) : c(c) {}
};
public:
elem operator()(value_type c) const { return elem(c); }
bool operator()(int a, int b) const { return X[a] < X[b]; } // for is_sorted
bool operator()(int a, elem b) const { return X[a] < b.c; } // for find
bool operator()(elem a, int b) const { return a.c < X[b]; } // for find
explicit CompM(const RandIter X) : X(X) {}
};
template<class RandContainer, class Key, class Compare>
int upper(const RandContainer& a, int n, const Key& k, const Compare& comp) {
return std::upper_bound(a.begin(), a.begin() + n, k, comp) - a.begin();
}
template<class RandIter>
std::pair<int,int> lis2(RandIter X, std::vector<int>& P)
{
int n = P.size(); assert(n > 0);
std::vector<int> M(n);
CompM<RandIter> comp(X);
int L = 0;
for (int i = 0; i < n; ++i) {
int j = upper(M, L, comp(X[i]), comp);
P[i] = (j > 0) ? M[j-1] : -1;
if (j == L) L++;
M[j] = i;
}
return std::pair<int,int>(L, M[L-1]);
}
int main(int argc, char** argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s string\n", argv[0]);
return 3;
}
const char* X = argv[1];
int n = strlen(X);
if (n == 0) {
fprintf(stderr, "param string must not empty\n");
return 3;
}
std::vector<int> P(n), S(n), F(n);
std::pair<int,int> lt = lis2(X, P); // L and tail
int L = lt.first;
printf("Longest_increasing_subsequence:L=%d\n", L);
for (int i = lt.second; i >= 0; --i) {
if (!F[i]) {
int j, k = 0;
for (j = i; j != -1; j = P[j], ++k) {
S[k] = j;
F[j] = 1;
}
std::reverse(S.begin(), S.begin()+k);
for (j = 0; j < k; ++j)
printf("%c", X[S[j]]);
printf("\n");
}
}
return 0;
}

Resources