Finding Longest Path in Directed Acyclic Graph - algorithm

I need to find the longest path from node 0 for a set of Directed Acyclic Graphs. I am using the Longest Path Problem algorithm from Wikipedia. I have got the algorithm working for most graphs, but for others it doesn't give a correct result. The algorithm is:
private static int DAGLongestPath(Graph G) {
int n = G.order();
int[] topOrder = new int[n];
topOrder = topSort2(G);
for (int i = 0; i < topOrder.length; i++) {
topOrder[i] -= 1;
}
int[] lengthTo = new int[n];
for (int i = 0; i < n; i++) lengthTo[i] = 0;
for (int i = 0; i < topOrder.length; i++) { //for each vertex v in topOrder(G) do
ArrayList<Integer> neighbors = new ArrayList<Integer>();
neighbors = G.neighbors(topOrder[i]);
int v = topOrder[i];
for (int j = 0; j < neighbors.size(); j++) {
int w = neighbors.get(j);
if(lengthTo[w] <= lengthTo[v] + 1) {
lengthTo[w] = lengthTo[v] + 1;
}
}
}
int max = 0;
for (int i = 0; i < n; i++ ) {
max = Math.max(max, lengthTo[i]);
}
return max;
}
The graph implementation uses an Adjacency List to store the graphs. If I pass a graph like:
9 // Number of nodes
0: 1 2
1: 2 3 4
2: 4 8
3: 5 6
4: 6 7 8
5:
6:
7:
8: 7
I get the answer 5, which is correct. However, if I pass the graph:
8 // Number of nodes
0: 2 3
1:
2:
3: 5
4: 5
5: 2
6: 7
7: 4
Then I get 2, when the correct answer should be 3.
The TopSort2 algorithm I am using is:
public static int[] topSort2(Graph G){
int n = G.order();
int[] sort = new int[n];
int[] inDeg = new int[n];
for (int i=0; i<n; i++) inDeg[i] = G.inDegree(i);
int cnt = 0;
boolean progress = true;
//
while (progress){
progress = false;
for (int v=0; v<n; v++){
if (inDeg[v] == 0){
sort[v] = ++cnt;
progress = true;
inDeg[v] = -1;
ArrayList<Integer> nbrs = G.neighbors(v);
for (int u : nbrs){
inDeg[u] = inDeg[u] - 1;
}
}
} // for v
} // while nodes exist with inDegree == 0.
return sort;
}
DFS algorithms are:
private static int doDFS(Graph G, int v, int[] PreOrder, int[] PostOrder, countPair cnt){
PreOrder[v] = cnt.inc1();
int dfsTotal = 0;
ArrayList<Integer> nbrs = G.neighbors(v);
for (int i : nbrs) {
if (PreOrder[i] == 0) {
int dfsTemp = doDFS(G, i, PreOrder, PostOrder, cnt);
dfsTotal = Math.max(dfsTotal, dfsTemp);
}
}
PostOrder[v] = cnt.inc2();
if(nbrs.size() > 0 ) {
dfsTotal++;
}
return dfsTotal;
}
public static int DFS(Graph G, int v, int[] PreOrder, int[] PostOrder){
int n = G.order();
int total = 0;
for (int i=0; i<n; i++) PreOrder[i] = PostOrder[i] = 0;
countPair cnt = new countPair();
total = doDFS(G, v, PreOrder, PostOrder, cnt);
return total;
}
private static class countPair { // private counters for DFS search
int cnt1, cnt2;
int inc1() { return ++cnt1; }
int inc2() { return ++cnt2; }
}

I think the problem is your topSort2() function
In the int[] sort returned by the function, the index denotes the vertex and the content denotes the order. i.e. if you have sort[1] = 2, you mean vertex 1 is the second vertex
However when you use it, you take the content as the vertex. i.e. you take topOrder[i] as a vertex, while actually i should be the vertex

Related

Algorithm to check whether students can be allocated to classes as per their preferences

In a coding hackathon I got following problem :
There are K classes each having certain capacity. There are N students and each has one or two class preference. We need to print "YES" if all the students can be allocated to a class or else "NO".
For example :
N = 4
K = 3
capacity = {2,1,1}
preference = {"0","0,2","1","2"}
There are 4 students and 3 classes and as per their preferences following classes can be allocated:
Student
Classes
0
0
1
0
2
1
3
2
So the answer for the above scenario will be "YES"
What will be algorithm approach to solve the above problem?
Update:
I used Christian's explanation below to come up with following solution:
import java.util.*;
public class StudentAllocation{
public static void main(String args[]){
int N = 4;
int K = 3;
int capacity[] = {2,1,1};
String preference[] = {"0","0,2","1","2"};
System.out.println(canAllocate(N,K,capacity,preference));
}
public static String canAllocate(int N,int K,int c[],String p[]){
//Creating nodes for each student and capacity*class
//Also making one node for source and on node for sink
HashMap<String,Integer> nm = new HashMap<String,Integer>();
int n = 1;
for(int i = 0;i < N;i++){
nm.put("s"+i,n++);
}
for(int i = 0;i < c.length;i++){
for(int j = 0;j < c[i];j++){
nm.put("c"+i+j,n++);
}
}
n = n+1;
int[][] g = new int[n][n];
//connecting source to all student nodes
for(int i = 1;i <= N;i++){
g[0][i] = 1;
}
//connecting all capacity*class nodes to sink
for(int i = N+1;i < n-1;i++){
g[i][n-1] = 1;
}
//Connecting student node to all the capcity node of class of his preference
for(int i = 0;i < p.length;i++){
String ps = p[i];
String pst[] = ps.split(",");
for(int j = 0;j < pst.length;j++){
for(int k = 0;k < c[Integer.parseInt(pst[j])];k++){
g[nm.get("s"+i)][nm.get("c"+pst[j]+k)] = 1;
g[nm.get("s"+i)][nm.get("c"+pst[j]+k)] = 1;
}
}
}
//Using Ford Fulkerson to callculate max flow
// If max flow is equal to no of students then each student can be allocated to any class of his preference
//Making residual graph
int rg[][] = new int[n][n];
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
rg[i][j] = g[i][j];
}
}
int parent[] = new int[n];
int max_flow = 0;
int count = 0;
while(bfs(rg,0,n-1,parent)){
count++;
int path_flow = Integer.MAX_VALUE;
for(int i = n-1;i != 0;i = parent[i]){
path_flow = Math.min(path_flow,rg[parent[i]][i]);
}
max_flow = max_flow + path_flow;
for(int i = n-1;i != 0;i = parent[i]){
rg[parent[i]][i] -= path_flow;
rg[i][parent[i]] += path_flow;
}
}
if(max_flow == N){
return "YES";
}
return "NO";
}
public static boolean bfs(int rg[][],int u, int v, int[] p){
ArrayDeque<Integer> q = new ArrayDeque<Integer>();
q.offer(u);
int marked[] = new int[rg.length];
while(!q.isEmpty()){
u = q.poll();
marked[u] = 1;
for(int i = 0;i < rg[u].length;i++){
if(marked[i] != 1 && rg[u][i] > 0){
p[i] = u;
q.add(i);
if(i == v){
return true;
}
}
}
}
return false;
}
}
You can create a bipartite graph with student nodes on one side, and then on the other side create class*capacities nodes. Each node represent one spot in a class.
An edge from a student to a class node represents that this student is willing to take this spot. Note that a student is willing to take any spot in a class it has a preference to.
The problem then is to find a perfect matching in this graph. If such a matching exists it is a "YES", if not it is a "NO".
Here is a recursive algorithm. We consider the last student, try their first choice and
check if the problem for the remaining n-1 students can be solved. If not, try the second
choice (if any), and again, check the problem for the remaining students.
Here is an implementation in PHP (you can test it here):
<?php
function isSolvable($choices1, $choices2, $capacities, $n)
{
if($n==0)
return true; // No students left to allocate
// First choice of student $n
$c1 = $choices1[$n-1];
if($capacities[$c1]>0)
{
$capacities[$c1]--;
if(isSolvable($choices1, $choices2, $capacities, $n-1))
return true;
$capacities[$c1]++;
}
// Second choice of student $n
$c2 = $choices2[$n-1];
if($c2>=0 && $capacities[$c2]>0)
{
$capacities[$c2]--;
if(isSolvable($choices1, $choices2, $capacities, $n-1))
return true;
}
return false;
}
$choices1 = [0, 0, 1, 2];
$choices2 = [-1, 2, -1, -1];
$capacities = [2, 1, 1];
echo isSolvable($choices1, $choices2, $capacities, count($choices1)) ? 'YES' : 'NO';
?>

Find minimum cost of tickets

Find minimum cost of tickets required to buy for traveling on known days of the month (1...30). Three types of tickets are available : 1-day ticket valid for 1 days and costs 2 units, 7-days ticket valid for 7 days and costs 7 units, 30-days ticket valid for 30 days and costs 25 units.
For eg: I want to travel on [1,4,6,7,28,30] days of the month i.e. 1st, 4th, 6th ... day of the month. How to buy tickets so that the cost is minimum.
I tried to use dynamic programming to solve this but the solution is not giving me the correct answer for all cases. Here is my solution in Java :
public class TicketsCost {
public static void main(String args[]){
int[] arr = {1,5,6,9,28,30};
System.out.println(findMinCost(arr));
}
public static int findMinCost(int[] arr) {
int[][] dp = new int[arr.length][3];
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < 3; j++) {
if (j==0){
dp[i][j]= (i+1)*tCost[j];
}
else{
int c = arr[i]-tDays[j];
int tempCost = tCost[j];
int k;
if (c>=arr[0] && i>0){
for (k = i-1; k >= 0; k--) {
if (arr[k]<=c){
c = arr[k];
}
}
tempCost += dp[c][j];
int tempCostX = dp[i-1][j] + tCost[0];
tempCost = Math.min(tempCost,tempCostX);
}
dp[i][j] = Math.min(tempCost,dp[i][j-1]);
}
}
}
return dp[arr.length-1][2];
}
}
The solution doesn't work for {1,7,8,9,10} input, it gives 10 but the correct answer should be 9. Also, for {1,7,8,9,10,15} it give 13 but the correct is 11.
I have posted my solution not for other to debug it for me but just for reference. I was taken a bottom-up dynamic programming approach for this problem. Is this approach correct?
Let MC(d) denote the minimum cost that will pay for all trips on days 1 through d. The desired answer is then MC(30).
To calculate MC(d), observe the following:
If there's no trip on day d, then MC(d) = MC(d − 1).
As a special case, MC(d) = 0 for all d ≤ 0.
Otherwise, the minimum cost involves one of the following:
A 1-day pass on day d. In this case, MC(d) = MC(d − 1) + 2.
A 7-day pass ending on or after day d. In this case, MC(d) = min(MC(d − 7), MC(d − 6), …, MC(d − 1)) + 7.
And since MC is nondecreasing (adding a day never reduces the minimum cost), this can be simplified to MC(d) = MC(d − 7) + 7. (Hat-tip to Ravi for pointing this out.)
A 30-day pass covering the whole period. In this case, MC(d) = 25.
As you've realized, dynamic programming (bottom-up recursion) is well-suited to this.
For ease of coding, I suggest we start by converting the list of days into a lookup table for "is this a trip day?":
boolean[] isDayWithTrip = new boolean[31]; // note: initializes to false
for (final int dayWithTrip : arr) {
isDayWithTrip[dayWithTrip] = true;
}
We can then create an array to track the minimum costs, and populate it starting from index 0:
int[] minCostUpThroughDay = new int[31];
minCostUpThroughDay[0] = 0; // technically redundant
for (int d = 1; d <= 30; ++d) {
if (! isDayWithTrip[d]) {
minCostUpThroughDay[d] = minCostUpThroughDay[d-1];
continue;
}
int minCost;
// Possibility #1: one-day pass on day d:
minCost = minCostUpThroughDay[d-1] + 2;
// Possibility #2: seven-day pass ending on or after day d:
minCost =
Math.min(minCost, minCostUpThroughDay[Math.max(0, d-7)] + 7);
// Possibility #3: 30-day pass for the whole period:
minCost = Math.min(minCost, 25);
minCostUpThroughDay[d] = minCost;
}
And minCostUpThroughDay[30] is the result.
You can see the above code in action at: https://ideone.com/1Xx1fd.
One recursive solution in Python3.
from typing import List
def solution(A: List[int]) -> int:
if not any(A):
return 0
tickets = {
1: 2,
7: 7,
30: 25,
}
import sys
min_cost = sys.maxsize
size = len(A)
for length, price in tickets.items():
current_cost = price
idx = 0
last_day = A[idx] + length
while idx < size and A[idx] < last_day:
idx += 1
if current_cost > min_cost:
continue
current_cost += solution(A[idx:])
if current_cost < min_cost:
min_cost = current_cost
return min_cost
if __name__ == '__main__':
cases = {
11: [1, 4, 6, 7, 28, 30],
9: [1, 7, 8, 9, 10],
}
for expect, parameters in cases.items():
status = (expect == solution(parameters))
print("case pass status: %s, detail: %s == solution(%s)" %
(status, expect, parameters))
public class Main03v3
{
public static void main(String[] args)
{
int[] A = {1,7,8,9,10,15,16,17,18,21,25};
System.out.println("Traveling days:\r\n "+Arrays.toString(A));
int cost = solution(A);
System.out.println("\r\nMinimum cost is " + cost);
System.out.println("\r\n" + new String(new char[40]).replace("\0", "-"));
}
public static int solution(int[] A)
{
if (A == null) return -1;
int sevenDays = 7;
int dayCost = 2, weekCost = 7, monthCost = 25;
int ratio_WeekAndDays = weekCost / dayCost;
int len = A.length;
if (len == 0) return -1;
if (len <= 3) return len * dayCost;
int cost[] = new int[len];
int i = 0;
while (i < len)
{
int startIdx = i, endIdx = i + 1;
while (endIdx < len && A[endIdx]-A[startIdx] < sevenDays)
endIdx++;
if (endIdx-startIdx > ratio_WeekAndDays)
{
if (endIdx >= startIdx + sevenDays)
endIdx = startIdx + sevenDays;
int j = startIdx;
cost[j] = ((j == 0) ? 0 : cost[j-1]) + weekCost;
while (++j < endIdx) {
cost[j] = cost[j-1];
}
i = j;
}
else
{
cost[i] = ((i == 0) ? 0 : cost[i-1]) + dayCost;
i++;
}
}
int finalCost = Math.min(cost[len-1], monthCost);
return finalCost;
}
}
Find minimum cost of tickets in JavaScript
case 1 : if input is [1,7,8,9,10] then the required output is 9
case 2 : if input is [1,7,8,9,10,15] then the required output is 11
function calMinCosts(arr){
if(!arr || arr.length===0)
return 0;
var len = arr.length;
var costsOfDateArr = Array.apply(null,{length:arr[len-1]+1}).map(()=>0);
var price1=2,price2=7,price3=25;
var days=7;
var index=0,n=costsOfDateArr.length;
for(var i=1;i<n;i++){
if(i===arr[index]){
if(i>=days+1){
costsOfDateArr[i] = Math.min(costsOfDateArr[i-days-1]+price2, costsOfDateArr[i-1]+price1);
}else{
costsOfDateArr[i] = Math.min(costsOfDateArr[0]+price2, costsOfDateArr[i-1]+price1);
}
index+=1;
}else{
costsOfDateArr[i] = costsOfDateArr[i-1];
}
}
return Math.min(price3,costsOfDateArr[n-1]);
}
console.log(calMinCosts([1,7,8,9,10]))
console.log(calMinCosts([1,7,8,9,10,15]))
Here is the C++ solution including print outs
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
int compute(std::vector<int> &A)
{
int sum[A.size()][A.size()+1];
for (int i = 0; i < A.size(); i++)
{
for(int j =0; j < A.size(); j++)
{
sum[i][j]=2;
}
}
for (int k = 0; k < A.size();k++)
{
sum[k][A.size()]=0;
}
for (int i = 0; i < A.size(); i++)
{
for(int j = 0; j < A.size(); j++)
{
if (i!=j)
{
if (sum[i][i] != 7)
{
int temp = abs(A[j]-A[i]);
if (temp<7 && abs(j-i)>=3)
{
sum[i][i]=7;
sum[i][j]=7;
if (i>j)
{
for(int k = j;k < i;k++)
sum[i][k]=7;
}
else
{
for(int k = i;k < j;k++)
sum[i][k]=7;
}
}
}
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for(int j = 0; j < A.size(); ++j)
{
if (sum[i][j]==7)
{
sum[i][A.size()]+=1;
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for (int j = 0; j < A.size()+1; ++j)
std::cout<<sum[i][j]<<" ";
std::cout<<std::endl;
}
int result = 0;
int row = A.size()-1;
int column = A.size()-1;
while(1)
{
int value = sum[row][A.size()];
if (value == 0)
value=1;
int temp = sum[row][column];
result += temp;
row = row-value;
column = column-value;
while (sum[row][column+1]==7 && row>=0)
{
row-=1;
column-=1;
result+=2;
}
if (row < 0)
break;
}
return result;
}
int solution(std::vector<int> &A) {
if (A.size() > 24)
return 25;
if (A.size() <= 3)
return A.size() * 2;
return std::min(25,compute(A));
}
int main()
{
std::vector<int> AA={1,2,3,4,5,29,30};
std::vector<int> B={1,2,3,4,5};
std::vector<int> A={1,2,3,4,5,9,10,11,12,13,14,17,18,20,21};
std::vector<int> C={1,2,3,12};
std::vector<int> D={1,2,3,4,12,13,14,15,29,30};
std::vector<int> DD={1,2,3,4,5,14,17,18,19,20,23,28,29,30};
std::vector<int> CC={1,2,3,4,5,6,7,9,14,17,18,19,20,23,28,29,30};
std::cout<<solution(AA)<<std::endl;
std::cout<<solution(D)<<std::endl;
std::cout<<solution(B)<<std::endl;
std::cout<<solution(A)<<std::endl;
std::cout<<solution(C)<<std::endl;
std::cout<<solution(DD)<<std::endl;
std::cout<<solution(CC)<<std::endl;
return 0;
}
Solved using the same approach of bottom-up dynamic programming. Here is the full solution :
public class PublicTicketCost {
public static void main(String args[]){
int[] arr = {1,7,8,9,10,15,16,17,18,21,25};
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
System.out.println(minCost(arr, tDays, tCost));
}
public static int minCost(int[] arr, int[] tDays, int[] tCost) {
int[][] dp = new int[arr.length][tDays.length];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < tDays.length; j++) {
int prevDayIndex = findPrevDayIndex(arr,i,tDays,j);
int prevCost = prevDayIndex>=0 ? dp[prevDayIndex][tDays.length-1] : 0;
int currCost = prevCost + tCost[j];
if(j-1>=0){
currCost = Math.min(currCost, dp[i][j-1]);
}
dp[i][j] = currCost;
}
}
//print(dp);
return dp[arr.length-1][tDays.length-1];
}
private static void print(int arr[][]){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
private static int findPrevDayIndex(int[] arr, int i, int[] days, int j){
int validAfterDate = arr[i] - days[j];
if (validAfterDate<1){
return -1;
}
for (int k = i-1; k >= 0; k--) {
if (arr[k]<=validAfterDate){
return k;
}
}
return -1;
}
}
http://ideone.com/sfgxGo

How to modify algorithm to get all maximal matchings in bipartite graph?

I use the following code to find maximal matching in bipartite graph
(I've tried to add a few comments):
#include <iostream>
using namespace std;
// definition of lists elements
//-------------------------------
struct slistEl
{
slistEl * next;
int data;
};
// definition objective type queue
//---------------------------------
class queue
{
private:
slistEl * head;
slistEl * tail;
public:
queue();
~queue();
bool empty(void);
int front(void);
void push(int v);
void pop(void);
};
queue::queue()
{
head = tail = NULL;
}
queue::~queue()
{
while(head) pop();
}
bool queue::empty(void)
{
return !head;
}
int queue::front(void)
{
if(head) return head->data;
else return -10000;
}
void queue::push(int v)
{
slistEl * p = new slistEl;
p->next = NULL;
p->data = v;
if(tail) tail->next = p;
else head = p;
tail = p;
}
void queue::pop(void)
{
if(head)
{
slistEl * p = head;
head = head->next;
if(!head) tail = NULL;
delete p;
}
}
//---------------
// main part
//---------------
queue Q; // queue
int *Color; // colors of vertexes
slistEl **graf; // adjacency array
int **C; // matrix of capacity
int **F; // matrix of nett flow
int *P; // array of prev
int *CFP; // array of residual capacity
int n,m,fmax,cp,v,u,i,j; //
bool esc; //
slistEl *pr, *rr; // pointer for list elements
int main(int argc, char *argv[])
{
// n - number of vertexes
// m - number of edges
cin >> n >> m;
Color = new int [n];
graf = new slistEl * [n];
for(i = 0; i < n; i++)
{
graf[i] = NULL;
Color[i] = 0;
}
C = new int * [n+2];
F = new int * [n+2];
for(i = 0; i <= n + 1; i++)
{
C[i] = new int [n+2];
F[i] = new int [n+2];
for(j = 0; j <= n + 1; j++)
{
C[i][j] = 0;
F[i][j] = 0;
}
}
P = new int [n+2];
CFP = new int [n+2];
// reading edges definition and adding to adjacency list
for(i = 0; i < m; i++)
{
cin >> v >> u;
pr = new slistEl;
pr->data = u;
pr->next = graf[v];
graf[v] = pr;
pr = new slistEl;
pr->data = v;
pr->next = graf[u];
graf[u] = pr;
}
for(i = 0; i < n; i++){
cin>> Color[i];
}
for(i = 0; i < n; i++)
if(Color[i] == -1)
{
for(pr = graf[i]; pr; pr = pr -> next) // neighbours of blue
C[i][pr->data] = 1; // capacity to red
C[n][i] = 1; // capacity to source
}
else C[i][n+1] = 1; // capacity edges to outfall
//** Edmonds-Karp algorithm **
fmax = 0;
while(true)
{
for(i = 0; i <= n + 1; i++) P[i] = -1;
P[n] = -2;
CFP[n] = MAXINT;
while(!Q.empty()) Q.pop();
Q.push(n);
esc = false;
while(!Q.empty())
{
v = Q.front(); Q.pop();
for(u = 0; u <= n + 1; u++)
{
cp = C[v][u] - F[v][u];
if(cp && (P[u] == -1))
{
P[u] = v;
if(CFP[v] > cp) CFP[u] = cp; else CFP[u] = CFP[v];
if(u == n+1)
{
fmax += CFP[n+1];
i = u;
while(i != n)
{
v = P[i];
F[v][i] += CFP[n+1];
F[i][v] -= CFP[n+1];
i = v;
}
esc = true; break;
}
Q.push(u);
}
}
if(esc) break;
}
if(!esc) break;
}
// showing reuslts
if(fmax > 0)
for(v = 0; v < n; v++)
for(u = 0; u < n; u++)
if((C[v][u] == 1) && (F[v][u] == 1))
cout << v << " - " << u << endl;
cout << endl;
// cleaning
delete [] Color;
for(i = 0; i < n; i++)
{
pr = graf[i];
while(pr)
{
rr = pr;
pr = pr->next;
delete rr;
}
}
delete [] graf;
for(i = 0; i <= n + 1; i++)
{
delete [] C[i];
delete [] F[i];
}
delete [] C;
delete [] F;
delete [] P;
delete [] CFP;
return 0;
}
It returns only one maximal matching. For example for data:
6 7
0 3 0 5
1 3 1 4 1 5
2 3 2 5
1 1 1 -1 -1 -1
But there are more maximal matchings.
I don't know, how should I modify it to get all results and I would like to ask somebody for help. Thank you in advance.
That algorithm is only efficient to get you a maximum matching.
If you want all maximal matching you have to consider the case where any matching is a maximal matching. In that case you have N! possibilities.
Since you will need to visit all solutions your complexity will be O(N!) at least. Therefore, forget the code you have, you can just try all possible matchings using a recursive algorithm and keep the set of maximal matching you get.

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

Knapsack 0-1 path reconstruction (which items to take) [duplicate]

This question already has answers here:
How to find which elements are in the bag, using Knapsack Algorithm [and not only the bag's value]?
(4 answers)
Closed 2 years ago.
I know how to solve knapsack 0-1 problem with dynamic programming approach, but I am having troubles figuring out which items to take without compromising the complexity of O(N * C) (N items, C capacity).
Any ideas (I would prefer a bottom-up approach)?
Suppose, right now you're storing results in array bool[] a, where a[i] is true when sum i can be achieved.
You'll need another array int[] b, where b[i] is a last element you've placed into knapsack to achieve sum i.
So, where you had
a[i] = true;
you'll need
a[i] = true;
b[i] = current_item;
Then, finding which items can be taken to achieve sum i is a simple loop.
PS I use two arrays for simplicity, but obviously array a can be removed.
Here is a modification to reconstruct path in O(n) times
int knapsack(int weight[], int profit[], int no_of_items, int capacity) {
for (int var = 0; var <= capacity; ++var) {
dp[0][var] = 0;
}
for (int var = 0; var <= no_of_items; ++var) {
path[var] = false;
}
int using_item_i, without_using_item_i;
for (int i = 1; i <= no_of_items; ++i) {
for (int j = 1; j <= capacity; ++j) {
without_using_item_i = dp[i - 1][j];
using_item_i = 0;
if ((weight[i]) <= j) {
using_item_i = dp[i - 1][j - weight[i]] + profit[i];
}
if (using_item_i >= without_using_item_i) {
taken[i][j] = true;
dp[i][j] = using_item_i;
} else {
taken[i][j] = false;
dp[i][j] = without_using_item_i;
}
}
}
//Reconstructing back the path
int j = capacity;
for (int i = no_of_items; i >= 0; --i) {
if (taken[i][j]) {
path[i] = true;
cnt++;
}
j = j - weight[i];
}
return dp[no_of_items][capacity];
}
boolean[] solution = new boolean[nItems];
for (int i = nItems, c = maxCapacity; i > 0 && c > 0; i--) {
int iThItemAddedValue = value[i - 1][c - weights[i - 1]] + values[i - 1];
int iThItemInheritedValue = value[i - 1][c];
if (iThItemAddedValue > iThItemInheritedValue) {
solution[i - 1] = true;
c = c - weights[i - 1];
} else {
solution[i - 1] = false;
}
}
Check the sol in the attached image
public class Knapsackproblem {
private static int[][] cache;
public static void main(String[] args) {
int val[] = new int[]{60, 100, 120};
int wt[] = new int[]{10, 20, 30};
int W = 50;
int n = val.length;
System.out.println(knapSack(W, wt, val, n));
printValues(wt,val);
}
/**
* This method will find the result with
* more value with weight less than or equal
* to given weight
* #param w given weight
* #param wt arrays of weights
* #param val array of values
* #param n length of the array
* #return max value we can obtain
*/
private static int knapSack(int w, int[] wt, int[] val, int n) {
cache = new int[n+1][w+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= w; j++) {
if(j < wt[i-1]){
cache[i][j] = cache[i-1][j];
}else {
cache[i][j] = Math.max(cache[i-1][j],(cache[i-1][j-wt[i-1]])+val[i-1]);
}
}
}
for (int[] aCache : cache) {
System.out.println(Arrays.toString(aCache));
}
return cache[n][w];
}
private static void printValues(int[] wt, int[] val) {
int m = cache.length-1;
int n = cache[0].length-1;
util(wt,val,m,n);
}
private static void util(int[] wt, int[] val, int m, int n) {
if(m <=0 || n<=0) return;
if((cache[m][n] != cache[m-1][n]) && (cache[m][n] != cache[m][n-1])){
System.out.println(val[m-1]+"-->"+wt[m-1]);
util(wt, val, m-1, (n - wt[m - 1] + 1));
}else
if(cache[m][n] == cache[m-1][n]){
util(wt,val,m-1,n);
}
else if(cache[m][n] == cache[m][n-1])
util(wt,val,m,n-1);
else
util(wt,val,m,(n-val[m-1]+1));
}
}
https://www.dropbox.com/s/ish7t5vgy91fovt/Screenshot%202017-01-01%2015.16.31.png?dl=0
Print the tmpList in the caller and you will get the answer

Resources