Einfacher Algorithmus möglich?

Gast #5812225
Lesenswert?

Aloha,
gerade wollte ich einen vermeintlich einfachen Algorithmus runterhacken, 
musste aber feststellen dass meine Lösung nichts taugt ;-) Auch nach 
langem Grübeln habe ich noch keine optimale Lösung gefunden. Daher wende 
ich mich mal an die Superhirne hier im Forum :-)

Gegeben: n Einsen und m Nullen.
Gesucht: Die Ziffern sollen so in ein Array der Länge n+m verteilt 
werden, dass die Anzahl aufeinanderfolgender gleicher Ziffern möglichst 
klein ist.

Beispiel:
n=3 und m=3

-> [0,0,0,1,1,1] ist die schlechtest mögliche Lösung  (max. Länge 3)
-> [0,1,0,1,0,1] ist die optimale Lösung  (max. Länge 1)

Noch ein Beispiel:
n=1 und m=3
-> [0,0,1,0] wäre eine optimale Lösung (max. Länge 3)

Noch ein Beispiel:
n=9 und m=6
-> [1,1,0,1,1,0,1,1,0,1,1,0,1,0,0] wäre eine optimale Lösung  (max. 
Länge 2)

Ich hoffe die Aufgabe ist einigermaßen klar geworden?
Wenn jemand eine Zündende Idee hat, darf es mich gerne wissen lassen :-)


PS: Worum geht es hier eigentlich? Es sollen aus Blöcken von 
Video-Frames einige Frames entfernt werden. Diese sollen aber möglichst 
gleichmäßig verteilt sein, so dass das Ergebnis nachher so flüssig wie 
möglich erscheint.
Persönliche Seite #5812238
Lesenswert?

1
#include <stdio.h>
2
#include <stdlib.h>
3

4
void generate (unsigned int n, unsigned int m) {
5
  unsigned int cn = 0, cm = 0;
6
  
7
  while (cn < n || cm < m) {
8
    if (cn < n && (cn * m <= n * cm)) {
9
      fputs ("0, ", stdout);
10
      ++cn;
11
    } else {
12
      fputs ("1, ", stdout);
13
      ++cm;
14
    }
15
  }
16
  puts ("");
17
}
18

19
int main (int argc, char* argv []) {
20
  if (argc != 3) {
21
    fprintf (stderr, "Usage: %s Zeroes Ones\n", argv [0]);
22
    return 1;
23
  }
24
  generate (atoi (argv [1]), atoi (argv [2]));
25
}
So?
#5812241
Lesenswert?

Hallo Quixy,

Du lässt einfach alle (n+m)/n Frames einen Frame fallen.

Mit ein bisschen Optimierung kannst Du anstelle der Rundung auf ganze 
Frame-Nr. die Löschungen so verteilen, dass die ersten Frames alle

abgerundet[(n+m)/n] eine Löschung bekommen, und dahinter alle Frames mit

aufgerundet[(n+m)/n]

Dann ändert sich der Abstand der gelöschten Frames im gesamten Video nur 
an einer Stelle.
Bei der Berechnung der Standardabweichung des Löschungsabstandes macht 
das jedoch keinen Unterschied.

P.S.:
Haftungsausschluss: Bin kein Superhirn.
Gast #5812446
Lesenswert?

Niklas G. schrieb:
> #include <stdio.h>
> #include <stdlib.h>
>
> void generate (unsigned int n, unsigned int m).......

wenn ich dein Programm mit Parametern 3 4 aufrufe, dann bekomme ich als 
Lösung:
1
0, 1, 1, 0, 1, 0, 1,

Hier stehen zwei Einsen direkt nebeneinander. Man kann aber die 
Kombination
1
1010101

erzeugen.
Gast #5812500
Lesenswert?

Mein "Algorithmus":

n = Anzahl Einsen
m = Anzahl Nullen

p = min(m,n) = Anzahl der Paare
s = abs(n-m) = Anzahl der restlichen "single digits"

Annahme: n>m

1) Erzeuge p Pärchen "01"
2) An die ersten s Pärchen vorne eine "1" anhängen
Gast #5812508
Lesenswert?

zitter_ned_aso schrieb:
> Mein "Algorithmus":
>
> n = Anzahl Einsen
> m = Anzahl Nullen
>
> p = min(m,n) = Anzahl der Paare
> s = abs(n-m) = Anzahl der restlichen "single digits"
>
> Annahme: n>m
>
> 1) Erzeuge p Pärchen "01"
> 2) An die ersten s Pärchen vorne eine "1" anhängen

n = 7
m = 1
-> p = 1
-> s = 6
--> 101

Naja.
Persönliche Seite #5812518
Lesenswert?

zitter_ned_aso schrieb:
> Hier stehen zwei Einsen direkt nebeneinander.

Oh, stimmt. Das liegt an dem "<=" - bei der ersten Ziffer wird der 0 die 
Vorzug gegeben. Bei "<" hätte man das umgekehrte Problem. Der erste Teil 
der Bedingung ist wohl auch überflüssig. Außerdem kann man die 
wiederholte Multiplikation vermeiden, indem man direkt um n bzw. m 
inkrementiert. So geht es:
1
void generate (unsigned int n, unsigned int m) {
2
  unsigned int cn = 0, cm = 0;
3
  
4
  while (cn < n*m || cm < n*m) {
5
    if (cn < cm || (cn == cm && n >= m)) {
6
      fputs ("0, ", stdout);
7
      cn += m;
8
    } else {
9
      fputs ("1, ", stdout);
10
      cm += n;
11
    }
12
  }
13
  assert (cm == n*m);
14
  assert (cn == n*m);
15
  puts ("");
16
}
17

18
int main (int argc, char* argv []) {
19
  if (argc != 3) {
20
    fprintf (stderr, "Usage: %s Zeroes Ones\n", argv [0]);
21
    return 1;
22
  }
23
  generate (atoi (argv [1]), atoi (argv [2]));
24
}

Die Folge wird also bei ausgeglichenem Verhältnis (u.a. am Anfang) mit 
der Ziffer fortgesetzt, von der es mehr geben soll, wobei 0 Vorzug hat 
wenn n=m.

Mit dem Algorithmus könnte man auch einen Takt durch einen gebrochenen 
Faktor teilen - wenn man die Funktion im Takt der Eingabefrequenz 
aufruft, man bei "1" einen Puls ausgibt und bei "0" nicht, ist der 
Teilungsfaktor (n+m)/m. Jittert natürlich ziemlich, der Duty-Cycle ist 
komisch, aber alle n+m Takte stimmt das Teiler-Verhältnis wieder, d.h. 
der Fehler ist nicht kumulativ.
Gast #5812520
Lesenswert?

Jemand schrieb:
> n = 7
> m = 1
> -> p = 1
> -> s = 6
> --> 101
>
> Naja.



zitter_ned_aso schrieb:
> 1) Erzeuge p Pärchen "01"
> 2) An die ersten s Pärchen vorne eine "1" anhängen

3) keine Pärchen mehr vorhanden an das letze Pärchen die restlichen 
(s-p) Einsen anhängen ;-)

Hier in C:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <math.h>
4

5
int main(void){
6
    
7
    int num_1=7;
8
    int num_0=1;
9

10
    int x1, x2;
11

12
    if(num_1>num_0){
13
        x1=1;
14
        x2=0;
15
    }
16
    else{
17
        x1=0;
18
        x2=1; 
19
    }
20
    
21
    //zusammengesetztes Array deklarieren   
22
    int arr_len=num_1+num_0; 
23
    int* arr=malloc(sizeof(int)*arr_len);
24

25
    //zusammengestztes Array initialisieren
26
    int i=0;
27
    int j=0;
28
    int k=0;
29
    int num_of_pairs=(num_1>num_0)?num_0:num_1;
30
    int num_of_single_digits=abs(num_1-num_0);
31
    while(i<arr_len){
32
        //"single digits" vor dem Paerchen
33
        if(j++<num_of_single_digits)
34
            *(arr+i++)=x1;
35
        //die Paerchen 
36
        if(k++<num_of_pairs){
37
            *(arr+i++)=x2;
38
            *(arr+i++)=x1;
39
        }
40
    }
41
   
42
    //Array ausgeben
43
    for(int i=0; i<arr_len; i++){
44
        printf("%d", *(arr+i)); 
45
    }
46
    puts("");
47

48
    free(arr);
49

50
    return 0;
51
}
Gast #5812553
Lesenswert?

zitter_ned_aso schrieb:
> 3) keine Pärchen mehr vorhanden an das letze Pärchen die restlichen
> (s-p) Einsen anhängen ;-)

Und das würde nicht reichen!

Denn es kommt dann  10111111 raus. Und 11101111 is besser.

Also muss man dann diese (s-p) Einsen immer abwechselnd anhängen: vorne, 
hinten, vorne hinten.... Und das bei "jedem" Pärchen :-( Und auch das 
würde nicht gehen.

Denn n=6, m=2 würde 10111011 liefern. Und 11011011 wäre besser!  Meine 
Güte, das ist vielleicht eine Aufgabe....
Gast #5812580
Lesenswert?

1
n=20  => 1,1,1,1.....
2
m=2   => 0,0
3

4
2 Pärchen:  01  01 (Reihenfolge wichtig)
5

6
noch 20-2=18 "single digits".
7

8
=> single digits vor jedem Pärchen einfügen: 101 101
9
und an das letzte Pärchen anhängen: 101 1011 --->max. Länge =2
10

11
noch 20-5=15 "single digits" zu verteilen.
12

13
Wieder vorne, vorne, hinten einfügen:  1101 110111 --> max. Länge =3 (besser geht's nicht)
14

15
20-8=12
16

17
vorne, vorne, hinten: 11101 11101111 ----> max=4 
18

19
20-11=9
20

21
vorne, vorne, hinten: 111101 1111011111 --->max=5
22

23
20-14=6
24

25
vorne, vorne, hinten: 1111101 111110111111 --->max=6
26

27
20-17=3
28

29
vorne, vorne, hinten: 11111101 11111101111111 --->max=7

Vielleicht so. Es sieht zumindest besser aus.
#5812776
Lesenswert?

Quixy schrieb:
> PS: Worum geht es hier eigentlich? Es sollen aus Blöcken von
> Video-Frames einige Frames entfernt werden.
das heißt aber dass es nicht nur einmal stattfindet sondern Ende=Anfang 
ist

zitter_ned_aso schrieb:
> Ich habe es so verstanden:
>
> 1 0  111 0 1 1
>
> --> max. Länge = 3
>
> 11 0 11 0 11
>
> --> max. Länge = 2

damit stimmt das nicht mehr, dann ist:

10111011-10111011
-> max Länge = 3

11011011-11011011
-> max Länge = 4

zitter_ned_aso schrieb:
> Denn n=6, m=2 würde 10111011 liefern. Und 11011011 wäre besser!  Meine
> Güte, das ist vielleicht eine Aufgabe....
ist dann auch nicht mehr so schlecht, denn:
10111011-10111011
-> immer noch max Länge 3
und das "bessere":
11011011-11011011 hat dann max Länge 4

von weiter oben:
zitter_ned_aso schrieb:
> wenn ich dein Programm mit Parametern 3 4 aufrufe, dann bekomme ich als
> Lösung:0, 1, 1, 0, 1, 0, 1,
>
> Hier stehen zwei Einsen direkt nebeneinander. Man kann aber die
> Kombination
> 1010101
wenn man die Lösungen "Ringförmig" betrachtet sind sie wieder identisch

heut ist mir zu spät um darüber weiter nachzudenken, aber ich glaube die 
Lösung schlägt hier grad nen falschen Weg ein. Außer ein Block 
entspricht dem gesammten Video, aber dafür sind die Zahlen etwas klein, 
niemand hat nur 20 Frames in einem Video. Wenn es nur 2-3 Blöcke gibt 
sollte man natürlich Anfang+Ende als solche betrachtet optimieren, aber 
bei mehreren Sekunden-Minuten Video ist es ausreichend davon auszugehen 
dass jeder Block einen Vorgänger und Nachfolger hat.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren