Get lowest price on sum of combinations in given array - php

This code is working fine when the array length is 8 or 10 only. When we are checking this same code for more than 10 array length.it get loading not showing the results.
How do reduce my code. If you have algorithm please share. Please help me.
This program working flow:
$allowed_per_room_accommodation =[2,3,6,5,3,5,2,5,4];
$allowed_per_room_price =[10,30,60,40,30,50,20,60,80];
$search_accommodation = 10;
i am get subsets = [5,5],[5,3,2],[6,4],[6,2,2],[5,2,3],[3,2,5]
Show lowest price room and then equal of 10 accommodation; output like as [5,3,2];
<?php
$dp=array(array());
$GLOBALS['final']=[];
$GLOBALS['room_key']=[];
function display($v,$room_key)
{
$GLOBALS['final'][] = $v;
$GLOBALS['room_key'][] = $room_key;
}
function printSubsetsRec($arr, $i, $sum, $p,$dp,$room_key='')
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if ($i == 0 && $sum != 0 && $dp[0][$sum]) {
array_push($p,$arr[$i]);
array_push($room_key,$i);
display($p,$room_key);
return $p;
}
// If $sum becomes 0
if ($i == 0 && $sum == 0) {
display($p,$room_key);
return $p;
}
// If given sum can be achieved after ignoring
// current element.
if (isset($dp[$i-1][$sum])) {
// Create a new vector to store path
// if(!is_array(#$b))
// $b = array();
$b = $p;
printSubsetsRec($arr, $i-1, $sum, $b,$dp,$room_key);
}
// If given $sum can be achieved after considering
// current element.
if ($sum >= $arr[$i] && isset($dp[$i-1][$sum-$arr[$i]]))
{
if(!is_array($p))
$p = array();
if(!is_array($room_key))
$room_key = array();
array_push($p,$arr[$i]);
array_push($room_key,$i);
printSubsetsRec($arr, $i-1, $sum-$arr[$i], $p,$dp,$room_key);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
function printAllSubsets($arr, $n, $sum,$get=[])
{
if ($n == 0 || $sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
// $dp = new bool*[$n];
$dp = array();
for ($i=0; $i<$n; ++$i)
{
// $dp[$i][$sum + 1]=true;
$dp[$i][0] = true;
}
// Sum arr[0] can be achieved with single element
if ($arr[0] <= $sum)
$dp[0][$arr[0]] = true;
// Fill rest of the entries in dp[][]
for ($i = 1; $i < $n; ++$i) {
for ($j = 0; $j < $sum + 1; ++$j) {
// echo $i.'d'.$j.'.ds';
$dp[$i][$j] = ($arr[$i] <= $j) ? (isset($dp[$i-1][$j])?$dp[$i-1][$j]:false) | (isset($dp[$i-1][$j-$arr[$i]])?($dp[$i-1][$j-$arr[$i]]):false) : (isset($dp[$i - 1][$j])?($dp[$i - 1][$j]):false);
}
}
if (isset($dp[$n-1][$sum]) == false) {
return "There are no subsets with";
}
$p;
printSubsetsRec($arr, $n-1, $sum, $p='',$dp);
}
$blockSize = array('2','3','6','5','3','5','2','5','4');
$blockvalue = array('10','30','60','40','30','50','20','60','80');
$blockname = array("map","compass","water","sandwich","glucose","tin","banana","apple","cheese");
$processSize = 10;
$m = count($blockSize);
$n = count($processSize);
// sum of sets in array
printAllSubsets($blockSize, $m, $processSize);
$final_subset_room = '';
$final_set_room_keys = '';
$final_set_room =[];
if($GLOBALS['room_key']){
foreach ($GLOBALS['room_key'] as $set_rooms_key => $set_rooms) {
$tot = 0;
foreach ($set_rooms as $set_rooms) {
$tot += $blockvalue[$set_rooms];
}
$final_set_room[$set_rooms_key] = $tot;
}
asort($final_set_room);
$final_set_room_first_key = key($final_set_room);
$final_all_room['set_room_keys'] = $GLOBALS['room_key'][$final_set_room_first_key];
$final_all_room_price['set_room_price'] = $final_set_room[$final_set_room_first_key];
}
if(isset($final_all_room_price)){
asort($final_all_room_price);
$final_all_room_first_key = key($final_all_room_price);
foreach ($final_all_room['set_room_keys'] as $key_room) {
echo $blockname[$key_room].'---'. $blockvalue[$key_room];
echo '<br>';
}
}
else
echo 'No Results';
?>

I'm assuming your task is, given a list rooms, each with the amount of people it can accommodate and the price, to accommodate 10 people (or any other quantity).
This problem is similar to 0-1 knapsack problem which is solvable in polynomial time. In knapsack problem one aims to maximize the price, here we aim to minimize it. Another thing that is different from classic knapsack problem is that full room cost is charged even if the room is not completely occupied. It may reduce the effectiveness of the algorithm proposed at Wikipedia. Anyway, the implementation isn't going to be straightforward if you have never worked with dynamic programming before.
If you want to know more, CLRS book on algorithms discusses dynamic programming in Chapter 15, and knapsack problem in Chapter 16. In the latter chapter they also prove that 0-1 knapsack problem doesn't have trivial greedy solution.

Related

Check Final Amount is allowed to accept with Available Denominations of country in PHP

Need to make custom function to check amount with available denominations.
code i make :
$amount = 100;
$notes_aval = array(20,50,100,500,2000);//available currency notes
$is_allowed = 0; //not allowed
foreach($notes_aval as $note){
if (fmod($amount,$note) == 0) {
$is_allowed = 1;//allowed
}
}
echo $is_allowed;
But this is not working out for all cases.
For exam : i have denominations = array (20,50);
with amount 90 is not allowed, but it should be allowed by 20*2 + 50*1 = 90
in the example of denominations = array (20,50) ,if amount 1110 should be acceptable with 1110 = 20*53 + 50*1
Try both modular divisions
function validateCurrency($amount)
{
$requestdAmount = $amount;
$valueUnder = 0;
$notes = array(20, 50,100,500,2000);
$is_allowed = 0;
if(in_array($amount, $notes)){
return $is_allowed = 1;
}
$numOccurance = ceil($amount/$notes[0]);
$arraySums = [];
foreach ($notes as $key => $value) {
for ($i=1; $i <= $numOccurance; $i++) {
if($value * $i == $amount) {
return $is_allowed = 1;
}
$arraySums[$key][] = $value * $i;
}
}
for ($i=0; $i < count($arraySums); $i++) {
for ($j=$i+1; $j < count($arraySums); $j++) {
foreach ($arraySums[$i] as $key => $value) {
foreach ($arraySums[$j] as $key2 => $toBeMul) {
if($value+$toBeMul == $amount) {
return $is_allowed = 1;
}
}
}
}
}
return $is_allowed;
}
// Driver Code
$amount = 40;
$is_allowed = validateCurrency($amount);
echo $is_allowed;
die();
It will work
You need to start exchange from largest value until your amount is smaller than largest note (eg 2000). Then you go this same with lower note (eg 500), and again with lower. When amount is smaller than lowest value (eg. 20) then you cannot exchange this amount.
So:
We start with 2270
We check for largest note - it's 2000.
Now we know we have 2000 and 270 (2270 - 2000) rest
Now we check again for largest value - it's 200
So we have 2000, 200 and 70 (270 - 200) rest
Now largest not possible is 50
So we have 2000, 200, 50 and 20 (70 - 50) rest
Now largest is 20 and we have 2000, 200, 50, 20 and rest is 0
As rest is smaller than lowest note then we can stop checking.
If rest is 0 we know we can exchange, if rest is larger than 0 then we cannot. Additionally we also have list of notes we can use for exchange (2000, 200, 50, 20).
function checkDenomination($amount){
$notes = array(2000,500,100,50,20); //it's easier if they are reversed
$smallestNote = 20;
$result = [];
while($amount >= $smallestNote) { //we will repeat until we can exchange
foreach($notes as $note) {
if ($amount >= $note) { //we check for largest value we can exchange
$result[] = $note;
$amount -= $note; //as we have hit, we can deduct it from amount;
break;
}
}
}
return ($amount > 0) ? false : $result; //return false if we cannot exchange this amount or array with notes we can exchange for full amount
}
var_dump(checkDenomination(100));
var_dump(checkDenomination(23424));
var_dump(checkDenomination(25000));
var_dump(checkDenomination(222));

Check if Variable is smaller than others, and which one its smaller than. PHP

I have been working on my scoring system and came accros this.
I have 4 vars.
$newscore
$score1
$score2
$score3
I want to see if new score is lower than the 3 others, and if so which ones. The scoring system requires you to have the lowest possible score.
I have the following code:
if($newscore > $score1){
if($newscore > $score2){
if($newscore < $score3){
//has to be score3 to replace.
}
}else{
...
}
}
But what I'm wondering is if I will have to continue on with all these if statements, or is there something a lot shorter and easier? I need to replace the the score that it is smaller than, but not the one its larger than. Score 1 2 and 3 are all the players stats. And if I do have to continue on with all the if statements, how would the code look (its baffling my logic)?
you should probably use an array
$scores = array(8, 15, 10); //previous scores
$new_score = 5;
$new_score_smallest = true;
foreach($scores as $score) {
if($score < $new_score) {
$new_score_smallest = false;
}
}
if($new_score_smallest) {
echo "Best score!";
}
else {
echo "Not the best score :(";
}
If you only want to remember the 3 best scores:
$scores = array(5, 6, 8);
$new_score = 7;
for($i = 0; $i < count($scores); $i++) {
if($new_score < $scores[$i]) {
$scores[$i] = $new_score;
break;
}
}
You could do something like the following:
EDIT: As you're using a database, you would execute the query similar to this:
SELECT scores FROM scores_table replacing the table name and column name with your corresponding data.
$scores = [$score1, $score2] // add as many as you like
$new_score = $scores[0]; // assign a baseline
foreach ($scores as $score) {
if ($score < $new_score) {
$new_score = $score;
}
}
Hope that helps.
You can use array_search and min
$newscore = 2;
$scores = array($score1, $score2, $score3);
if($newscore < min($scores)){
$scores[array_search(min($scores), $scores)] = $newscore;
}
array $score lowest score will be updated if $newscore is inferior
Put your scores in an array or anything iterable (like a query result, whether you use PDO or mysqli).
Let's say your scores are in $scores array (it will be the same if $score is a PDOStatement for example) and ordered (use ORDER ASC in your query):
$scores = [105, 201, 305];
$newscore = '186';
$hiscore = false;
$beaten = [];
foreach ($score as $k => $score) {
if ($newscore > $score) {
$hiscore = true;
$beaten[] = $score;
unset($scores[$k]);
}
}
if ($hiscore) {
echo 'New high score!'.PHP_EOL;
echo 'Better than '.implode(', ', $beaten).PHP_EOL;
echo 'But not better than '.implode(', ', $scores);
} else {
echo 'Try harder!';
}
<?php
$newscore = 78;
$score1 = 23;
$score2 = 201;
$score3 = 107;
$max = max([$score1, $score2, $score3]);
if ($max < $newscore) {
echo "New best score ! ({$newscore})";
} else {
echo "Not the best score !\nCurrent: {$newscore}\nBest: {$max}";
}

2D Cluster algorithm

I am analyzing images and need a fast clustering algorithm which searches for the center of the biggest center.
A sample data set might look like this:
$x = array(6,9,7,0,0,0,4,0,0,6,6,3);
As you see there are 3 clusters in the array.
The result I am looking for is the array position of the center of the cluster with the highest sum.
In the example above this would be 1 as $x[1] is the center of the biggest cluster 6+9+7(=22).
Any ideas?
Whichever way you go, you'll have to walk through the array at least once. The following algorithm does this in one pass without any additional sorting/searching - although I admit that it still may not be the most efficient one. Note that if the biggest cluster has an even number of elements, then it'll return the "lower" mid-point (e.g. for a cluster with indices 0, 1, 2, 3 it will return 1) - this can be easily adjusted in the last line of computation ($mid = ...).
$input = array(6,9,7,0,0,0,4,0,0,6,6,3);
$clust = array(0, 0, 0);
$st = -1;
$sum = 0;
for($i=0; $i<count($input); $i++) {
if($input[$i] == 0) {
if($i == 0) {
continue;
}
elseif($input[$i - 1] == 0) {
continue;
}
else {
if($clust[2] < $sum) {
$clust = array($st, $i - 1, $sum);
}
}
}
else {
if($i == 0 || $input[$i - 1] == 0) {
$st = $i;
$sum = 0;
}
$sum += $input[$i];
}
}
if(end($input) != 0 && $clust[2] < $sum) {
$clust = array($st, $i - 1, $sum);
}
if($clust[2] > 0) {
$mid = (int)(($clust[1] - $clust[0]) / 2);
echo $clust[0] ."->". $mid ."->" . $clust[1] ." = ". $clust[2];
}
else {
echo "No clusters found";
}

PHP "Maximum execution time"

I'm trying to program my own Sine function implementation for fun but I keep getting :
Fatal error: Maximum execution time of 30 seconds exceeded
I have a small HTML form where you can enter the "x" value of Sin(x) your looking for and the number of "iterations" you want to calculate (precision of your value), the rest is PhP.
The maths are based of the "Series definition" of Sine on Wikipedia :
--> http://en.wikipedia.org/wiki/Sine#Series_definition
Here's my code :
<?php
function factorial($int) {
if($int<2)return 1;
for($f=2;$int-1>1;$f*=$int--);
return $f;
};
if(isset($_POST["x"]) && isset($_POST["iterations"])) {
$x = $_POST["x"];
$iterations = $_POST["iterations"];
}
else {
$error = "You forgot to enter the 'x' or the number of iterations you want.";
global $error;
}
if(isset($x) && is_numeric($x) && isset($iterations) && is_numeric($iterations)) {
$x = floatval($x);
$iterations = floatval($iterations);
for($i = 0; $i <= ($iterations-1); $i++) {
if($i%2 == 0) {
$operator = 1;
global $operator;
}
else {
$operator = -1;
global $operator;
}
}
for($k = 1; $k <= (($iterations-(1/2))*2); $k+2) {
$k = $k;
global $k;
}
function sinus($x, $iterations) {
if($x == 0 OR ($x%180) == 0) {
return 0;
}
else {
while($iterations != 0) {
$result = $result+(((pow($x, $k))/(factorial($k)))*$operator);
$iterations = $iterations-1;
return $result;
}
}
}
$result = sinus($x, $iterations);
global $result;
}
else if(!isset($x) OR !isset($iterations)) {
$error = "You forgot to enter the 'x' or the number of iterations you want.";
global $error;
}
else if(isset($x) && !is_numeric($x)&& isset($iterations) && is_numeric($iterations)) {
$error = "Not a valid number.";
global $error;
}
?>
My mistake probably comes from an infinite loop at this line :
$result = $result+(((pow($x, $k))/(factorial($k)))*$operator);
but I don't know how to solve the problem.
What I'm tring to do at this line is to calculate :
((pow($x, $k)) / (factorial($k)) + (((pow($x, $k))/(factorial($k)) * ($operator)
iterating :
+ (((pow($x, $k))/(factorial($k)) * $operator)
an "$iterations" amount of times with "$i"'s and "$k"'s values changing accordingly.
I'm really stuck here ! A bit of help would be needed. Thank you in advance !
Btw : The factorial function is not mine. I found it in a PhP.net comment and apparently it's the optimal factorial function.
Why are you computing the 'operator' and power 'k' out side the sinus function.
sin expansion looks like = x - x^2/2! + x^3/3! ....
something like this.
Also remember iteration is integer so apply intval on it and not floatval.
Also study in net how to use global. Anyway you do not need global because your 'operator' and power 'k' computation will be within sinus function.
Best of luck.
That factorial function is hardly optimal—for speed, though it is not bad. At least it does not recurse. It is simple and correct though. The major aspect of the timeout is that you are calling it a lot. One technique for improving its performance is to remember, in a local array, the values for factorial previously computed. Or just compute them all once.
There are many bits of your code which could endure improvement:
This statement:
while($iterations != 0)
What if $iterations is entered as 0.1? Or negative. That would cause an infinite loop. You can make the program more resistant to bad input with
while ($iterations > 0)
The formula for computing a sine uses the odd numbers: 1, 3, 5, 7; not every integer
There are easier ways to compute the alternating sign.
Excess complication of arithmetic expressions.
return $result is within the loop, terminating it early.
Here is a tested, working program which has adjustments for all these issues:
<?php
// precompute the factorial values
global $factorials;
$factorials = array();
foreach (range (0, 170) as $j)
if ($j < 2)
$factorials [$j] = 1;
else $factorials [$j] = $factorials [$j-1] * $j;
function sinus($x, $iterations)
{
global $factorials;
$sign = 1;
for ($j = 1, $result = 0; $j < $iterations * 2; $j += 2)
{
$result += pow($x, $j) / $factorials[$j] * $sign;
$sign = - $sign;
}
return $result;
}
// test program to prove functionality
$pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620;
$x_vals = array (0, $pi/4, $pi/2, $pi, $pi * 3/2, 2 * $pi);
foreach ($x_vals as $x)
{
$y = sinus ($x, 20);
echo "sinus($x) = $y\n";
}
?>
Output:
sinus(0) = 0
sinus(0.78539816339745) = 0.70710678118655
sinus(1.5707963267949) = 1
sinus(3.1415926535898) = 3.4586691443274E-16
sinus(4.7123889803847) = -1
sinus(6.2831853071796) = 8.9457384260403E-15
By the way, this executes very quickly: 32 milliseconds for this output.

IMEI validation function

Does anybody know a PHP function for IMEI validation?
Short solution
You can use this (witchcraft!) solution, and simply check the string length:
function is_luhn($n) {
$str = '';
foreach (str_split(strrev((string) $n)) as $i => $d) {
$str .= $i %2 !== 0 ? $d * 2 : $d;
}
return array_sum(str_split($str)) % 10 === 0;
}
function is_imei($n){
return is_luhn($n) && strlen($n) == 15;
}
Detailed solution
Here's my original function that explains each step:
function is_imei($imei){
// Should be 15 digits
if(strlen($imei) != 15 || !ctype_digit($imei))
return false;
// Get digits
$digits = str_split($imei);
// Remove last digit, and store it
$imei_last = array_pop($digits);
// Create log
$log = array();
// Loop through digits
foreach($digits as $key => $n){
// If key is odd, then count is even
if($key & 1){
// Get double digits
$double = str_split($n * 2);
// Sum double digits
$n = array_sum($double);
}
// Append log
$log[] = $n;
}
// Sum log & multiply by 9
$sum = array_sum($log) * 9;
// Compare the last digit with $imei_last
return substr($sum, -1) == $imei_last;
}
Maybe can help you :
This IMEI number is something like this: ABCDEF-GH-IJKLMNO-X (without “-” characters)
For example: 350077523237513
In our example ABCDEF-GH-IJKLMNO-X:
AB is Reporting Body Identifier such as 35 = “British Approvals Board of Telecommunications (BABT)”
ABCDEF is Type Approval Code
GH is Final Assembly Code
IJKLMNO is Serial Number
X is Check Digit
Also this can help you : http://en.wikipedia.org/wiki/IMEI#Check_digit_computation
If i don't misunderstood, IMEI numbers using Luhn algorithm . So you can google this :) Or you can search IMEI algorithm
Maybe your good with the imei validator in the comments here:
http://www.php.net/manual/en/function.ctype-digit.php#77718
But I haven't tested it
Check this solution
<?php
function validate_imei($imei)
{
if (!preg_match('/^[0-9]{15}$/', $imei)) return false;
$sum = 0;
for ($i = 0; $i < 14; $i++)
{
$num = $imei[$i];
if (($i % 2) != 0)
{
$num = $imei[$i] * 2;
if ($num > 9)
{
$num = (string) $num;
$num = $num[0] + $num[1];
}
}
$sum += $num;
}
if ((($sum + $imei[14]) % 10) != 0) return false;
return true;
}
$imei = '868932036356090';
var_dump(validate_imei($imei));
?>
IMEI validation uses Luhn check algorithm. I found a link to a page where you can validate your IMEI. Furthermore, at the bottom of this page is a piece of code written in JavaScript to show how to calculate the 15th digit of IMEI and to valid IMEI. I might give you some ideas. You can check it out here http://imei.sms.eu.sk/index.html
Here is a jQuery solution which may be of use: https://github.com/madeinstefano/imei-validator
good fun from kasperhartwich
function validateImei($imei, $use_checksum = true) {
if (is_string($imei)) {
if (ereg('^[0-9]{15}$', $imei)) {
if (!$use_checksum) return true;
for ($i = 0, $sum = 0; $i < 14; $i++) {
$tmp = $imei[$i] * (($i%2) + 1 );
$sum += ($tmp%10) + intval($tmp/10);
}
return (((10 - ($sum%10)) %10) == $imei[14]);
}
}
return false;
}

Categories