I am trying to get all permutations of an array in CBMC.
For small cases, e.g., [1,2,3], I suppose I can write
i1 = nondet()
i2 = nondet()
i3 = nondet()
assume (i > 0 && i < 4); ...
assume (i1 != i2 && i2 != i3 && i1 != i3);
// do stuffs with i1,i2,i3
But with larger elements, the code will be very messy.
So my question is that is there a better/general way to express this?
Building on Craig's suggestion of using an array, you could loop over the values you want to permute, and nodeterministically select a location that has not been taken. For example, a loop like this (where sequence is pre-initalized with -1 for all values).
for(int i = 1; i <= count; ++i) {
int nondet;
assume(nondet >= 0 && nondet < count);
// ensure we don't pick a spot already picked
assume(sequence[nondet] == -1);
sequence[nondet] = i;
}
So a full program would look something like this:
#include <assert.h>
#include <memory.h>
int sum(int *array, int count) {
int total = 0;
for(int i = 0; i < count; ++i) {
total += array[i];
}
return total;
}
int main(){
int count = 5; // 1, ..., 6
int *sequence = malloc(sizeof(int) * count);
// this isn't working - not sure why, but constant propagator should
// unroll the loop anyway
// memset(sequence, -1, count);
for(int i = 0; i < count; ++i) {
sequence[i] = -1;
}
assert(sum(sequence, count) == -1 * count);
for(int i = 1; i <= count; ++i) {
int nondet;
__CPROVER_assume(nondet >= 0);
__CPROVER_assume(nondet < count);
__CPROVER_assume(sequence[nondet] == -1); // ensure we don't pick a spot already picked
sequence[nondet] = i;
}
int total = (count * (count + 1)) / 2;
// verify this is a permuation
assert(sum(sequence, count) == total);
}
However, this is pretty slow for values >6 (though I haven't compared it against your approach - it doesn't get stuck unwinding, it gets stuck solving).
Related
The problem is to create an array of player ranks based on 2 other arrays: leaderboard and player scores. More explanations of the problem here: https://www.hackerrank.com/challenges/climbing-the-leaderboard/problem.
The code below is a spaghetti but it's working fine. But, for large size of ranked array(200000 elements for example), it times out. I'm not asking for code to copy/paste. I just wanna know if there is a way to optimize this code.
int* climbingLeaderboard(int ranked_count, int* ranked, int player_count, int* player, int* result_count) {
*result_count=player_count;
// remove duplicates
int removed=0;
for(int i=0, j=1; i<ranked_count-removed; i++, j++){
if(ranked[i]==ranked[j]){
for(int k=j; k<ranked_count-removed; k++)
ranked[k]=ranked[k+1];
removed++;
}
}
int newsize=ranked_count-removed;
// create an array to store ranks then fill it
int* positions=malloc(newsize*sizeof(int));
positions[0]=1;
for(int i=0, j=1; j<newsize; i++, j++){
positions[j]=(ranked[j]<ranked[i])? (positions[i]+1) : positions[i];
}
// create and fill the results array using binary search
int* res = malloc(player_count*sizeof(int));
int start=0, end=newsize-1, middle=(start+end)/2;
int j, k=newsize-1;
for(int i=0; i<player_count; i++){
if(i>0&&player[i]==player[i-1]){
*(res+i)=(*(res+(i-1)));
continue;
}
if(player[i]>=ranked[middle]){
*(res+i)=positions[middle];
j=middle-1;
while(j>=0){
if(player[i]>=ranked[j])
*(res+i)=positions[j];
else if(j==k)
*(res+i)=positions[j]+1;
else break;
--j;
}
start=0; end=middle-1;
}
else{
*(res+i)=positions[newsize-1]+1;
j=newsize-1;
while(j>=middle){
if(player[i]>=ranked[j])
*(res+i)=positions[j];
else if(j==k)
*(res+i)=positions[j]+1;
else break;
--j;
}
start=middle+1; end=newsize-1;
}
middle=(start+end)/2;
}
free(positions);
return res;
}
The initial loop to remove duplicates has a potential quadratic time complexity. You can achieve linear complexity using the 2 finger approach:
int removed = 0;
for (int i = 1, j = 1; j < ranked_count; j++) {
if (ranked[i - 1] != ranked[j])
ranked[i++] = ranked[j];
else
removed++;
}
More generally, the argument arrays should not be changed in spite of the sloppy prototype given:
int *climbingLeaderboard(int ranked_count, int *ranked,
int player_count, int *player,
int *result_count);
Here are simple steps I would recommend to solve this problem:
allocate and initialize a ranking array with the ranking for each of the scores in the ranked array. Be careful to allocate ranked_count + 1 elements.
allocate a result array res of length player_count, set the result_count to player_count.
starting with pos = ranked_count, for each entry i in player:
locate the position pos where the entry would be inserted in the ranking array using binary search between position 0 and the current pos inclusive. Make sure you find the smallest entry in case of duplicate scores.
set res[i] to ranking[pos]
free the ranking array
return the res array.
Here is a simple implementation:
int *climbingLeaderboard(int ranked_count, int *ranked,
int player_count, int *player,
int *result_count)
{
if (player_count <= 0) {
*result_count = 0;
return NULL;
}
int *ranking = malloc(sizeof(*ranking) * (ranked_count + 1));
int rank = 1;
ranking[0] = rank;
for (int i = 1; i < ranked_count; i++) {
if (ranked[i] != ranked[i - 1])
rank++;
ranking[i] = rank;
}
ranking[ranked_count] = rank + 1;
int *res = malloc(sizeof(*res) * player_count);
*result_count = player_count;
int pos = ranked_count;
for (int i = 0; i < player_count; i++) {
int start = 0;
while (start < pos) {
int middle = start + (pos - start) / 2;
if (ranked[middle] > player[i])
start = middle + 1;
else
pos = middle;
}
res[i] = ranking[pos];
}
free(ranking);
return res;
}
Look for ways to use "branchless" to improve execution speed:
positions[0]=1;
for(int i=0, j=1; j<newsize; i++, j++){
positions[j]=(ranked[j]<ranked[i])? (positions[i]+1) : positions[i];
}
becomes
positions[0] = 1;
for( int i = 0, j = 1; j < newsize; i++, j++ )
positions[j] = positions[i] + (ranked[j] < ranked[i]);
Other than this, I don't even want to try to sort out what this code is attempting.
This is the task I have got:
I need to write a function (not recursive) which has two parameters.
An array of integers.
An integer representing the size of the array.
The function will move the duplicates to an end of the array.
And will give the size of the different digits.
Example:
5 , 2 , 4 , 5 , 6 , 7 , 2, n = 7
we will get back 5 , 2 , 4 , 6 , 7 , 5 , 2 and 5
We must keep the original sort as it is (which means like in example 5 must)
It does not matter how we sort the duplicates ones but just keep the sort for the original array as it is)
The function has to print the number of different digits (like in example 5)
The the input range of numbers in array [-n,n]
I can only use 1 additional array for help.
It has to be O(n)
I tried it so many times and feel like am missing something. Would appreciate any advice/suggestions.
int moveDup(int* arr, int n)
{
int* C = (int*)calloc(n * 2 + 1, sizeof(int));
assert(C);
/*int* count = C + n;*/
int *D = arr[0];
int value = 0, count = 0;
for (int i = 0; i < n; i++)
{
value = arr[i];
if (C[value + n] == 0)
{
*D = arr[i];
D++;
count++;
}
C[value + n] = C[value + n] + 1;
}
while (1 < C[value + n])
{
*D = i;
D++;
C[value + n]--;
}
free(C);
return count;
}
This algorithm will produce the required results in O(n) arithmetic complexity:
Input is an array A with n elements indexed from A0 to An−1 inclusive. For each Ai, −n ≤ Ai ≤ n.
Create an array C that can be indexed from C−n to C+n, inclusive. Initialize C to all zeros.
Define a pointer D. Initialize D to point to A0.
For 0 ≤ i < n:
If CAi=0, copy Ai to where D points and advance D one element.
Increment CAi.
Set r to the number of elements D has been advanced from A0.
For −n ≤ i ≤ +n:
While 1 < CAi:
Copy i to where D points and advance D one element.
Decrement CAi.
Release C.
Return r. A contains the required values.
A sample implementation is:
#include <stdio.h>
#include <stdlib.h>
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int moveDuplicates(int Array[], int n)
{
int *memory = calloc(2*n+1, sizeof *Array);
if (!memory)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
int *count = memory + n;
int *destination = Array;
for (int i = 0; i < n; ++i)
// Count each element. If it is unique, move it to the front.
if (!count[Array[i]]++)
*destination++ = Array[i];
// Record how many unique elements were found.
int result = destination - Array;
// Append duplicates to back.
for (int i = -n; i <= n; ++i)
while (0 < --count[i])
*destination++ = i;
free(memory);
return result;
}
int main(void)
{
int Array[] = { 5, 2, 4, 5, 6, 7, 2 };
printf("There are %d different numbers.\n",
moveDuplicates(Array, NumberOf(Array)));
for (int i = 0; i < NumberOf(Array); ++i)
printf(" %d", Array[i]);
printf("\n");
}
here is the right answer, figured it out by myself.
int moveDup(int* arr, int n)
{
int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
assert(seen_before);
int val = 0, count = 0, flag = 1;
int j = 0;
for (int i = 0; i < n; i++)
{
val = arr[i];
if (seen_before[arr[i] + n] == 0)
{
seen_before[arr[i] + n]++;
count++;
continue;
}
else if (flag)
{
j = i + 1;
flag = 0;
}
while (j < n)
{
if (seen_before[arr[j] + n] == 0)
{
count++;
seen_before[arr[j] + n]++;
swap(&arr[i], &arr[j]);
j++;
if (j == n)
{
free(seen_before);
return count;
}
break;
}
/*break;*/
j++;
if (j == n)
{
free(seen_before);
return count;
}
}
}
}
second right answer
int* mem = (int*)calloc(2 * n + 1, sizeof * arr);
assert(mem);
int* count = mem + n;
int* dest = arr;
for (i = 0; i < n; ++i)
{
if (count[arr[i]]++ == 0)
{
*dest = arr[i];
*dest++;
}
}
res = dest - arr;
for (i = -n; i <= n; ++i)
{
while (0 < --count[i])
{
*dest++ = i;
}
}
free(mem);
return res;
I am writing a program to read an integer n (0 < n <= 150) and find the smallest prime p and consecutive prime q such that q - p >= n.
My code works, but it runs for about 10 seconds for larger n.
#include <stdio.h>
#include <stdlib.h>
int isPrimeRecursive(int x, int i){
if (x <= 2){
return (x == 2 ? 1:0);
}
if (x % i == 0){
return 0;
}
if (i * i > x){
return 1;
}
return isPrimeRecursive(x, i+1);
}
int findSuccessivePrime(int x){
while (1){
x++;
if (isPrimeRecursive(x, 2)){
return x;
}
}
return 0;
}
int findGoodGap(int n, int *arr){
int prime = findSuccessivePrime(n*n);
while (1){
int gap;
int succPrime;
succPrime = findSuccessivePrime(prime);
gap = succPrime - prime;
if (gap >= n){
arr[0] = succPrime;
arr[1] = prime;
return gap;
}
prime = succPrime;
}
return 0;
}
int main(int argc, char *argv[]){
int n;
int arr[2];
scanf("%d", &n);
int goodGap;
goodGap = findGoodGap(n, arr);
printf("%d-%d=%d\n", arr[0], arr[1], goodGap);
return 0;
}
How can I make the program more efficient? I can only use stdio.h and stdlib.h.
The algorithm is very inefficient. You're recalculating the same stuff over and over again. You could do like this:
int n;
// Input n somehow
int *p = malloc(n * sizeof *p);
for(int i=0; i<n; i++) p[i] = 1; // Start with assumption that all numbers are primes
p[0]=p[1]=0; // 0 and 1 are not primes
for(int i=2; i<n; i++)
for(int j=i*2; j<n; j+=i) p[j] = 0;
Now, p[i] can be treated as a boolean that tells if i is a prime or not.
The above can be optimized further. For instance, it's quite pointless to remove all numbers divisible by 4 when you have already removed all that are divisible by 2. It's a quite easy mod:
for(int i=2; i<n; i++) {
while(i<n && !p[i]) i++; // Fast forward to next prime
for(int j=i*2; j<n; j+=i) p[j] = 0;
}
As Yom B mentioned in comments, this is a kind of memozation pattern where you store result for later use, so that we don't have to recalculate everything. But it takes it even further with dynamic programming which basically means using memozation as a part of the algorithm itself.
An example of pure memozation, that's heavily used in the C64 demo scene, is precalculating value tables for trigonometric functions. Even simple multiplication tables are used, since the C64 processor is MUCH slower at multiplication than a simple lookup. A drawback is higher memory usage, which is a big concern on old machines.
I think it would be a good approach to have all of the prime numbers found and store it in an array; in that case you wouldn't need to do divisions from scratch to find out whether a number is a prime number or not
This is the algorithm which checks if the number "n" is prime simply by doing divisions
bool isPrime(int n) {
if(n <= 1) return false;
if(n < 4) return true;
if(n % 2 == 0) return false;
if(n < 9) return true;
if(n % 3 == 0) return false;
int counter = 1;
int limit = 0;
while(limit * limit <= n) {
limit = limit * 6;
if(n % (limit + 1) == 0) return false;
if(n % (limit - 1) == 0) return false;
}
return true;
}
If you use the algorithm above which its time complexity is in order of sqrt(n) , your overall time complexity would be more than n^2
I suggest you to use "Sieve of Eratosthenes" algorithm to store prime numbers in an array
Check out this link
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Here is the code. I used optimized sieve in Main function.
#include <iostream>
using namespace std;
void Sieve(bool* list, const int n);
void OptimizedSieve(bool* list, const int n);
int main() {
bool list[100 / 2];
for(int i = 0; i < 100 / 2; i++) list[i] = true;
OptimizedSieve(list, 100 / 2);
for(int i = 0; i < 100 / 2; i++){
if(list[i]) cout << (2 * i) + 1 << endl;
}
return 0;
}
void Sieve(bool* list, const int n){
list[0] = false;
list[1] = false;
for(int p = 2; p * p <= n; p++){
if(!list[p]) continue;
for(int j = p * p; j < n; j += p){
if(list[j] == true) list[j] = false;
}
}
}
void OptimizedSieve(bool* list, const int n){
list[0] = false;
for(int p = 3; p * p <= n; p += 2){
if(!list[(2 * p) + 1]) continue;
for(int j = p * p; j <= n; j += 2 * p){
int index = (j - 1) / 2;
if(list[index]) list[index] = false;
}
}
}
I have a task where I have to fill an array with 16 random numbers, in random indexes.
4 of those elements have to be -1, and all the other left indexes have to be 0-15, but different from another, meaning it is impossible for two different indexes have the same number (0-15).
Filling 4 random indexes is easy, and so is filling the other indexes with random numbers between 0-15, but how do I feel them in such way that they are necessarily different from each other?
There are also two more conditions which complicate this task much more, the first one is that the number of the index cannot have the same number within it, meaning arr[3] == 3 is impossible, and another condition is that
(m[p] == j && m[j] == mp && m != j)
is something that we must take care of so it won't happen. For example, if arr[2] == 0 and arr[0] == 2, we have to change it so it won't happen.
I'm so confused, I had literally sat 8 hours yesterday in front of this, trying all sort of things, and I have no idea, honestly..
void FillArray(int *sites, int length)
{
int checkarr[N] = { 0 };
int i,
cnt = 0,
j = 0,
t = 0,
k,
times = 0;
int *p = sites;
while (cnt < C)
{
i = rand() % length;
if (p[i] - 1)
cnt = cnt;
p[i] = -1;
cnt++;
}
while (j < length)
{
if (p[j] == -1) j++;
else
{
p[j] = rand() % length;
checkarr[p[j]]++;
j++;
}
}
j =0;
while (j<length)
{
for (k=0; k<length;k++)
{
while (checkarr[k] > 1)
{
while (t < length)
{
if (p[j] == p[t] && p[j] != -1 && j != t)
{
checkarr[p[t]]--;
p[t] = rand() % length;
checkarr[p[t]]++;
times++;
}
else t++;
}
if (times < 11)
{
j++;
t = 0;
times = 0;
}
}
}
}
}
I tried using the Fisher-Yates shuffle method, but for somereason it doesn't even fill the array. I don't know why
while (j
if (p[j] == -1)
j++;
else {
while (m < length) {
m = rand() % length;
if (helpingArray[m] != -2)
{
p[j] = helpingArray[m];
helpingArray[m] = -2;
j++;
}
else if (helpingArray[m] == -2)
{
j = j;
}
for (w = 0; w < length; w++)
{
if (helpingArray[w] == -2)
count++;
}
if (count == 12) {
m = length;
}
}
}
}
}
I hope this will help, I tried to stay in the line with your first draft and what you were going for, just to note that this should work for an N length array. I changed the conditions on your second while to check the conditions before placing the value- and now you don't need to go over the set array and check and update the values.
you can also go another way as was commented here and just fill the array with values with help of one aux array to check each value is used only once and then randomly swap the indexes under the conditions.
I wrote this down but I didn't run tests- so make sure you understand whats going on and upgrade it to your needs. I do recommend using only one aux array, easy on memory and less whiles and checks.
GOOD LUCK
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 16
#define C 4
void FillArray(int *sites, int length) {
/*these aux arrays will keep track if an index was fill of if a value was used*/
int checkarrIndex[N] = { 0 };
int checkarrVal[N] = { 0 };
int i, cnt = 0, full=0; /*full is when all index are filled */
int *p = sites;
while (cnt < C) {
i = rand() % length;
if (checkarrIndex[i] == 0) /* checkarrIndex will let you know if an index has been gvin a value*/
{
++checkarrIndex[i]; /*now checkarrIndex[i] will be one so this index is now not valid for placement next time*/
p[i] = -1;
++full;/*at the end of this while full will equal 4*/
cnt++;
}
}
while (full < length) /*here you need to draw a random index and a random value for it,
not just a random value for a fixed index like you did, if I got this wrong just
go over the free indexes and place a rand value one at a time in the same manner*/
{
int index; /*will store new random index */
int value; /*will store new random value */
index = rand() % N;
value = rand() % N;/*max value is 15*/
while(checkarrIndex[index]!= 0) /*check if this index was already placed */
{
index = rand() % N; /*try a another one */
}
/*I made this while loop to check all the con before filling the array */
while(checkarrVal[value]!= 0 || p[value]== index || index == value) /*check if this value was already used or if p[i]=j&&p[j]=i cond happens and make sure p[a] != a*/
{
value = rand() % N; /*try a another one */
}
++checkarrIndex[index];/*set index as used */
++checkarrVal[value];/*set value as used */
p[index] = value;
++full; /*another place was filled */
}
}
static void PrintArray(int* arr, size_t size)
{
int i = 0 ;
for (i = 0 ; i< size; ++i)
{
printf("%d| ", arr[i]);
}
printf("\n");
}
int main(void)
{
int array[N] = {0};
FillArray(array, N);
PrintArray(array, N);
return 0;
}
I'm not completely sure, but I think the following meets all your special constraints [hopefully].
The random list function is a variation on Fisher Yates. You could recode it to use Durstenfeld if you wish.
I'm not sure that the constraints can be done cleanly in a single pass. That is, apply them while generating the random list.
What I've done is to generate a simple random list. Then, try to detect/fix (by swapping) some of the constraint violations.
Then, fill with negative values, trying to fix the self constraint violations if possible.
If that can't be done, repeat the whole process.
Anyway, here is my version. I split up the large function into several smaller ones. I also added a check function and a diagnostic loop. It is quite a bit different from yours, but other answers did this as well:
#include <stdio.h>
#include <stdlib.h>
#define NEG 4
int opt_N;
int opt_v;
int opt_T;
#ifdef DEBUG
#define dbg(_fmt...) \
do { \
if (opt_v) \
printf(_fmt); \
} while (0)
#else
#define dbg(_fmt...) /**/
#endif
// prtarray -- print array
void
prtarray(int *arr,int len)
{
int idx;
int val;
int hangflg = 0;
int cnt = 0;
for (idx = 0; idx < len; ++idx) {
val = arr[idx];
if (val < 0)
printf(" [%2.2d]=%d",idx,val);
else
printf(" [%2.2d]=%2.2d",idx,val);
hangflg = 1;
if (++cnt >= 8) {
printf("\n");
cnt = 0;
hangflg = 0;
continue;
}
}
if (hangflg)
printf("\n");
}
// fillrand -- generate randomized list (fisher yates?)
void
fillrand(int *arr,int len)
{
char idxused[len];
char valused[len];
int fillcnt = 0;
int idx;
int val;
for (idx = 0; idx < len; ++idx) {
idxused[idx] = 0;
valused[idx] = 0;
}
for (fillcnt = 0; fillcnt < len; ++fillcnt) {
// get random index
while (1) {
idx = rand() % len;
if (! idxused[idx]) {
idxused[idx] = 1;
break;
}
}
// get random value
while (1) {
val = rand() % len;
if (! valused[val]) {
valused[val] = 1;
break;
}
}
arr[idx] = val;
}
}
// swap2 -- swap elements that are (e.g.) arr[i] == arr[arr[i]])
int
swap2(int *arr,int len)
{
int idx;
int lhs;
int rhs;
int swapflg = 0;
dbg("swap2: ENTER\n");
for (idx = 0; idx < len; ++idx) {
lhs = arr[idx];
rhs = arr[lhs];
// don't swap self -- we handle that later (in negfill)
if (lhs == idx)
continue;
if (rhs == idx) {
dbg("swap2: SWAP idx=%d lhs=%d rhs=%d\n",idx,lhs,rhs);
arr[idx] = rhs;
arr[lhs] = lhs;
swapflg = 1;
}
}
dbg("swap2: EXIT swapflg=%d\n",swapflg);
return swapflg;
}
// negfill -- scan for values that match index and do -1 replacement
int
negfill(int *arr,int len)
{
int idx;
int val;
int negcnt = NEG;
dbg("negfill: ENTER\n");
// look for cells where value matches index (e.g. arr[2] == 2)
for (idx = 0; idx < len; ++idx) {
val = arr[idx];
if (val != idx)
continue;
if (--negcnt < 0)
continue;
// fill the bad cell with -1
dbg("negfill: NEGFIX idx=%d val=%d\n",idx,val);
arr[idx] = -1;
}
// fill remaining values with -1
for (; negcnt > 0; --negcnt) {
while (1) {
idx = rand() % len;
val = arr[idx];
if (val >= 0)
break;
}
dbg("negfill: NEGFILL idx=%d\n",idx);
arr[idx] = -1;
}
dbg("negfill: EXIT negcnt=%d\n",negcnt);
return (negcnt >= 0);
}
// fillarray -- fill array satisfying all contraints
void
fillarray(int *arr,int len)
{
while (1) {
// get randomized list
fillrand(arr,len);
if (opt_v)
prtarray(arr,len);
// swap elements that are (e.g. arr[i] == arr[arr[i]])
while (1) {
if (! swap2(arr,len))
break;
}
// look for self referential values and do -1 fill -- stop on success
if (negfill(arr,len))
break;
}
}
// checkarray -- check for contraint violations
// RETURNS: 0=okay
int
checkarray(int *arr,int len)
{
int idx;
int lhs;
int rhs;
int negcnt = 0;
int swapflg = 0;
dbg("checkarray: ENTER\n");
if (opt_v)
prtarray(arr,len);
for (idx = 0; idx < len; ++idx) {
lhs = arr[idx];
if (lhs < 0) {
++negcnt;
continue;
}
rhs = arr[lhs];
if (rhs == idx) {
printf("checkarray: PAIR idx=%d lhs=%d rhs=%d\n",idx,lhs,rhs);
swapflg = 2;
}
if (lhs == idx) {
printf("checkarray: SELF idx=%d lhs=%d\n",idx,lhs);
swapflg = 1;
}
}
if (negcnt != NEG) {
printf("checkarray: NEGCNT negcnt=%d\n",negcnt);
swapflg = 3;
}
dbg("checkarray: EXIT swapflg=%d\n",swapflg);
return swapflg;
}
int
main(int argc,char **argv)
{
char *cp;
int *arr;
--argc;
++argv;
opt_T = 100;
opt_N = 16;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'N':
opt_N = (cp[2] != 0) ? atoi(cp + 2) : 32;
break;
case 'T':
opt_T = (cp[2] != 0) ? atoi(cp + 2) : 10000;
break;
case 'v':
opt_v = ! opt_v;
break;
}
}
arr = malloc(sizeof(int) * opt_N);
for (int tstno = 1; tstno <= opt_T; ++tstno) {
printf("\n");
printf("tstno: %d\n",tstno);
fillarray(arr,opt_N);
if (checkarray(arr,opt_N))
break;
prtarray(arr,opt_N);
}
free(arr);
return 0;
}
My C is rusty, and I don't want to implement a Fisher-Yates shuffle or deal with the bad behavior of C PRNGs, so I'm expressing the algorithm in pseudo-code. Okay, I lie. It's Ruby, but it reads like pseudo-code and is heavily commented to show the logic of the solution. Consider the comments to be the solution, and the stuff in between a concrete illustration that the algorithm being described actually works.
N = 16
# Create + populate an array containing 0,...,N-1
ary = Array.new(N) { |i| i }
# Shuffle it
ary.shuffle!
# Iterate through the array. If any value equals its index, swap it with
# the value at the next index, unless it's the last array element
ary.each_index { |i| ary[i], ary[i + 1] = ary[i + 1], ary[i] if ary.length - i > 1 && ary[i] == i }
# If the last element equals its index, swap it with any other element
# selected at random. The rand function generates a random integer
# between 0, inclusive, and its argument, exclusive.
last = ary.length - 1
if ary[last] == last
random_index = rand(last)
ary[last], ary[random_index] = ary[random_index], ary[last]
end
# Replace 4 randomly selected entries with -1
4.times { ary[rand(ary.length)] = -1 }
# The array now contains unique elements (except for the -1's),
# none of which are equal to their index value
p ary
# Produces, e.g.: [4, 10, -1, 5, 9, -1, 15, 14, 7, 8, 12, 1, -1, 0, -1, 2]
All of this takes O(N) work. If your last constraint is violated, reject the solution and retry.
I believe the following generates a solution to the constraints with uniform distribution over all the solutions that satisfy the constraints:
Put the numbers 0 to 15 in pool A.
Put the numbers 0 to 15 in pool B.
12 times, draw a number a from pool A and a number b from pool B (in each case drawing randomly with uniform distribution and removing the drawn number from its pool, so it will not be chosen again later). Assign m[a] = b.
For each of the four numbers a remaining in pool A, assign m[a] = -1.
For all i from 0 to 15 (inclusive) and all j from i to 15 (inclusive), test whether m[i] == j && m[j] == i (note that this tests for both swaps and for m[i] == i, as it includes i == j). If such a case is found, reject the assignments and repeat the algorithm from the beginning.
I expect algorithmic improvements are possible to reduce or eliminate the frequency of rejection, but this establishes a baseline correct algorithm.
It is also possible to use a single pool instead of two and instead do some rearranging when the −1 elements are assigned, but the algorithm above is more easily expressed.
I am confused with your description. For placing N elements into N positions, I have a solution.
Question:
Place N elements into N positions with constraints:
(1) arr[i] != i;
(2) if arr[i] = j, then arr[j] != i
Solution:
For current element i (0 <= i < N)
(1) Find candidate position count
(a) count = N - i
(b) if arr[i] is empty => count -= 1
else if arr[arr[i]] is empty => count -= 1
(2) Select a random position from candidates
(a) relative_index = random() % count
(Note: relative_index means the position index in candidates)
(b) Find absolute_index by searching candidates
a candidate index j satisfies following constrains
<1> arr[j] is empy
<2> j != i
<3> j != arr[i] when arr[i] is not empty
I am trying to add two polynomial functions and store the answer into first one. So far I have this:
// co = coefficient, ex = exponent
void add_polynom(int co1[], int ex1[], int co2[], int ex2[])
{
int i, j;
for (i = 0; i < dataSize; i++)
{
for (j = 0; j < dataSize; j++)
{
if (ex1[i] == ex2[j])
{
co1[i] = co1[i] + co2[i];
co2[i] = 0;
}
}
}
}
Am I on the right track?
Your representation of polynomials is impractical:
you iterate in 2 nested loops (quadratic complexity) to try and match the corresponding terms of both polynomials, but if the second has a power that the first does not have, it will be missing in the sum.
you pass the degree as a global variable dataSize that may have an inappropriate value.
You should instead use an array of coefficients for all exponents from 0 to the degree of the polynomial and pass the destination polynomial and its degree this way:
/* add 2 polynomials into a destination array.
* count variables are the sizes of the arrays,
* ie 1 more than the degree of the polynomials.
* return the size of the resulting polynomial,
* potentially larger than the size of the destination array.
*/
int add_polynomials(int dest[], int dest_count,
const int co1[], int count1,
const int co2[], int count2) {
/* compute the result coefficients */
int i, count;
for (i = count = 0; i < dest_count; i++) {
int coef = 0;
if (i < count1)
coef += co1[i];
if (i < count2)
coef += co2[i];
dest[i] = coef;
if (coef != 0)
count = i + 1;
}
/* determine the result count */
for (; i < count1 && i < count2; i++) {
if (co1[i] + co2[i] != 0)
count = i + 1;
}
for (; i < count1; i++) {
if (co1[i] != 0)
count = i + 1;
}
for (; i < count2; i++) {
if (co2[i] != 0)
count = i + 1;
}
return count;
}
If you must use the given prototype and global definition for dataSize, you could use 2 nested loops indeed, but depending on how the exponents are used in both polynomials, it might be impossible to fit the result in the destination array:
the source polynomials can each have up to dataSize terms with any range of exponents. The resulting polynomial might have a total number of terms that exceeds dataSize and thus not representable in an array of size dataSize.
your code fails because you wrote co1[i] = co1[i] + co2[i]; instead of co1[i] = co1[i] + co2[j];, but you also modify co2[i], which is inappropriate and you miss the terms that are only present in co2/ex2.
If we can assume that the maximum exponent is less than dataSize, here is an efficient approach (linear time) that will generate a result in normalized form:
#define dataSize 50
// co = coefficients, ex = exponents
void add_polynom(int co1[], int ex1[], int co2[], int ex2[]) {
int res[dataSize] = { 0 };
int i, j;
for (i = 0; i < dataSize; i++) {
res[ex1[i]] += co1[i];
res[ex2[i]] += co2[i];
}
j = 0;
for (i = dataSize; i-- > 0;) {
if (res[i] != 0) {
co1[j] = res[i];
ex1[j] = i;
j++;
}
}
while (j < dataSize) {
co1[j] = ex1[j] = 0;
}
}
Take for example say 7x^3 + 2x + 1 as first and 5x^4 + 9x^2 as second polynomial. Now dataSize becomes 5(since higher degree of both is 4).
Now co1 would be {1, 2, 0, 7, 0} and co2 would be {0, 0, 9, 0, 5}.
for (i = 0; i < dataSize; i++)
{
co1[i] += co2[i];
}
Your interface is "suboptimal". It forces guarantees to to be made for it to work at all.
Use option 1 if you can guarantee that all values of exs1 and exs2 are in [0..(DATASIZE-1)].
Use option 2 if you can merely guarantee that there are fewer than DATASIZE different values in exs1 and exs2 combined.
Option 1
This solution's performance is bound by O(N).
#define DATASIZE 50
void panic(const char* msg) {
fprintf(stderr, msg);
exit(EXIT_FAILURE);
}
find_ex(ex,
// Assumes all values in exs1 are in [0..49].
// Assumes all values in exs2 are in [0..49].
void add_polynom(int cos1[], int exs1[], int cos2[], int exs2[]) {
int cos_sum[DATASIZE];
size_t i;
int exs1i, exs2i;
for (i=DATASIZE; i--; )
cos_sum[i] = 0;
for (i=DATASIZE; i--; ) {
if (exs1[i] < 0 || exs1[i] >= DATASIZE || exs2[i] < 0 || exs2[i] >= DATASIZE)
panic("add_polynom: Exponent out of range\n");
cos_sum[exs1[i]] += cos1[i];
cos_sum[exs2[i]] += cos2[i];
}
for (i=DATASIZE; i--; ) {
cos1[i] = cos_sum[i];
exs1[i] = i;
cos2[i] = 0;
/* exs2[i] = i; */
}
}
Option 2
This solution's performance is bound by O(N2). The bound can be reduced to O(N) by using an associative array instead of find_index_of_ex, but that's too much work for this answer.
#define DATASIZE 50
void panic(const char* msg) {
fprintf(stderr, msg);
exit(EXIT_FAILURE);
}
ssize_t find_index_of_ex(int ex, int cos[], int exs[], size_t size) {
ssize_t i;
for (i=0; i<size; ++i) {
if (exs[i] == ex) {
return i;
}
}
return -1;
}
// Assumes there are fewer than DATASIZE different values in exs1 and exs2 combined.
void add_polynom(int cos1[], int exs1[], int cos2[], int exs2[]) {
int cos_sum[];
int exs_sum[];
ssize_t lookup_is_by_ex[datasize];
size_t i, sum_count;
ssize_t i_sum;
for (i=DATASIZE; i--; ) {
cos_sum[i] = 0;
exs_sum[i] = 0;
}
sum_count = 0;
for (i=DATASIZE; i--; ) {
if (cos1[i] == 0)
continue;
i_sum = find_index_of_ex(exs1[i], exs_sum, sum_count);
if (i_sum >= 0)
cos_sum[i_sum] += cos1[i];
continue;
}
if (sum_count == DATASIZE)
panic("add_polynom: Too many different exponents\n");
cos_sum[sum_count] = cos1[i];
exs_sum[sum_count] = exs1[i];
++sum_count;
}
for (i=DATASIZE; i--; ) {
if (cos2[i] == 0)
continue;
i_sum = find_index_of_ex(exs2[i], exs_sum, sum_count);
if (i_sum >= 0)
cos_sum[i_sum] += cos2[i];
continue;
}
if (sum_count == DATASIZE)
panic("add_polynom: Too many different exponents\n");
cos_sum[sum_count] = cos2[i];
exs_sum[sum_count] = exs2[i];
++sum_count;
}
for (i=DATASIZE; i--; ) {
cos1[i] = cos_sum[i];
exs1[i] = exs_sum[i];
cos2[i] = 0;
/* exs2[i] = i; */
}
}