Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs
ASP German Homepage Homepage
 

Liste

.NET 2.0 (1)
.NET Allgemein (16)
.NET Fu (5)
ADO.NET (11)
Aprilscherz (3)
ASP Grundlagen (44)
ASP Tricks (83)
ASP.NET (44)
ASPIntranet.de (5)
C# (28)
Datenbank (44)
Dokumentation (4)
IIS 6.0 (1)
Komponenten (29)
Optimierung (10)
Server (21)
Sicherheit (34)
Tee Off (6)
VB.NET (6)
WAP (8)
Web Services (11)
XML (9)

RSS 2.0 - Die neuesten fünf Artikel auf AspHeute.com


 

Suchen





 

English Articles
Chinese Articles
Unsere Autoren
 
Link zu AspHeute
Impressum
Werben
Anfragen

Tee Off! Wolpertinger Genome Project

Geschrieben von: Bernhard Spuida
Kategorie: Tee Off

Nach langer Pause gab es wieder ein Golfturnier mit spannender Aufgabe und heroischen Mitspielern. Dieses Mal stammt die Aufgabenstellung von Alexander Veit. Die Aufgabe erscheint auf den ersten Blick kompliziert - weshalb auch eine Dauer von einem Monat für das Turnier festgesetzt wurde - ist aber mit erstaunlich wenig Schlägen zu bewätigen. Sehen wir sie uns an.

Die Aufgabenstellung

Bösewicht Venter möchte aus der DNA verschiedener alpenländischer Tierarten den Wolpertinger wieder erschaffen. Hans Blond, Topspion der Staatspolizei, soll ihm zuvor kommen und die Welt vor der Tyrannei, die Venter mit Hilfe des Wolpertingers zu errichten gedenkt (Wie soll das gehen?, der Autor) bewahren.

Da Blond keinen Plan von Molekulargenetik hat, bittet er seine Golffreunde um Mithilfe.

Regeln:

  1. Application("input") ist ein Array aus DNA-Fragmenten, Application("output") ist das rekonstruierte Wolpertinger-Gen.
  2. Ein DNA-Fragment ist eine nichtleere Zeichenkette aus [A-Z]*.
  3. Ein Gen ist ein DNA-Fragment.
  4. Zwei DNA-Fragmente passen zueinander, wenn sie überlappende Anfangs- oder Endstücke haben. Sie können dann miteinander verschmolzen werden. Bsp.:
     "A...O" und "Q...O"   passen nicht zusammen
    
     "AS...Z" und "U...AS" passen zusammen: "U...AS"
                                                         --> "U...AS...Z"
                                                "AS...Z"
    
  5. Gibt es mehr als eine Überlappung, so erhält beim Verschmelzen die größte den Vorzug. Bsp.:
     "A...GOLF"
               "OLF...U"    --> "A...GOLF...V", "OLF...U"
              "GOLF...V"
    
  6. Die Aufgaben werden so gewählt, daß sie eindeutig lösbar sind und alle Fragmente in das eine resultierende Gen eingebaut werden können. Insbesondere gibt es zu einem vorgegebenen Fragment höchstens ein Fortsetzungsstück mit maximaler Überlappung. Dieses passt dann nicht gleichzeitig mit gleicher oder größerer Überlappung an ein anderes Fragment als Fortsetzungsstück. Falls es hilft: das Anfangsstück des gesamten Gens beginnt immer mit einem A. Diese Eigenschaft hat kein anderes Fragment.

Diese Aufgabenstellung h&oumL;rt sich wirklich kompliziert und nahezu unlösbar an. Ist sie aber nicht, außerdem wurde ein Testprogramm zur Verfügung gestellt. Ein Beispiel für Rohdaten in der richtigen Sequenz:

ALLEK
    KUEHE
		   HETR 
        ETRINK
            NKENG
                GERNEM
                     MILCH

Ist doch nicht so schlimm wie man nach dem ersten Durchlesen der Aufgabenstellung meinen könnte, oder? Nach einigen Diskussionen auf der Mailingliste war allen klar was zu tun war und ein spannendes Turnier nahm seinen Lauf.

Leaderboard

  • 1. Johann Engbers 192
  • 2. Michele Marsching 199
  • 3. Markus Oestreicher 211
  • 4. Michael Schmidt 249
  • 5. Stefan Mayer 311
  • 6. Claudius Ceteras 318
  • 7. Daniel Daxl 462

Zwar recht wenige Teilnehmer, aber in Anbetracht der Aufgabe beachtlich. Und kein einziger Golfer lag zum Turnierende im Bunker. Die ersten beiden Plätze bekamen einen Intrexx Portal Manager respektive ein United Planet Zippo. Gratulation! Bedenkt man daß die längste gültige Einreichung bei 712 Schlägen (Stefan Mayer, auf 311 herunter gegolft) liegt, ist der Spizenplatz wirklich eindrucksvoll. Wir waren alle überrascht daß so etwas möglich ist.

Und nun wenden wir uns einigen Lösungen zu:

Stefan Mayer

Stefan hat eine wahrhaft heroische Verbesserung seines Scores erreicht. Von anfänglich 712 um 401 Schläge verbessert, alle Achtung.

Na dann - mein Code samt Erklärung:

<%Set V=Application
A=V("input")
u=ubound(a)
for g=0 to u
m=0
for i=0 to u
for j=0 to u
c=len(a(i)):d=len(a(j))
if d<c then c=d
p=0
for e=1 to c
if i<>j and right(a(i),e)=left(a(j),e) then p=e
next
if m<p then m=p:k=j:f=i
next
next
a(f)=a(f)&mid(a(k),m+1)
a(k)=""
next
v("output")=join(a,q)%>

Mein Problem ist aber, daß ich nicht mehr so genau weiß, wie ich darauf gekommen bin......

Auf jeden Fall funktioniert es so: Die einzelnen Fragmente werden jeder mit jedem auf Überschneidungen verglichen und da, wo sie am größten ist, wird Vorderteil und Hinterteil im Feld des Vorderteils gespeichert. Der Hinterteil wird auf "" gesetzt. Das ganze wiederholt er so oft es Felder im Array gibt.

Zum Schluß wird das Array zusammengebaut mit dem Trennzeichen LEER.

That's it

Michael Schmidt

Die beste Lösung ist ablauftechnisch ähnlich der von Stefan Mayer, aber doch um einiges kürzer. Außerdem erklärt uns Michael noch einen alternativen Ansatz den er aus Zeitgründen leider nicht einreichen konnte. Man muß nicht immer 'for'-Schleifen nehmen...

Platz da und Weg frei für meine Lösung:

<%set a=Application:i=a("input"):u=ubound(i)
for e=0to u
t=0
for m=0to u:for n=0to u
if m<>n then
for j=1to len(i(m))
if right(i(m),j)=left(i(n),j) and j>t then t=j:b=m:c=n
next
end if
next:next
i(b)=i(b)&mid(i(c),t+1)
i(c)=r
next
a("output")=i(b)%>

Also: Von der Technik ebenso wie bei Stefan, ich durchlaufe eine Schleife sooft wie Elemente übergeben wurden. Die Variable t wird bei jedem Schleifendurchlauf auf 0 gesetzt, in ihr wird später in der Schleife die maximale Überlappung gespeichert. Jetzt wird jedes Element im Input-Array mit jedem anderen verglichen, wobei mit einer Schleife, geschaut wird, wie hoch jeweils die Überlappung zum nächsten Element ist (right(i(m),j)=left(i(n),j)). Ist bei diesem Schleifendurchlauf noch keine höhere Überlappung gefunden worden (j>t), merke ich mir die Überlappung in t und die entsprechenden Elementnummern in b und c (t=j:b=m:c=n). Danach füge ich direkt im Input-Array den nicht überlappenden Rest des c-Elements (rechter Teil der Überlappung, mid(i(c),t+1)) an das b-Element (linker Teil der Überlappung, i(b)) und leere das Feld i(c). Am Ende von dat Janze steht nur noch im letzten i(b)-Feld etwas, was dann auch direkt an a("output") übergeben werden kann.

Übrigens: Zweite Lösung mit 237 Zeichen:

<%set a=Application:i=a("input"):u=ubound(i)
do
t=0
for m=0to u
for n=0to u
for j=1to len(i(m))
if right(i(m),j)=left(i(n),j) and j>t and m<>n then t=j:b=m:c=n
next
next
next
i(b)=i(b)&mid(i(c),t+1)
i(c)=r
loop while t
a("output")=i(b)%>

Funktionsweise wie oben, jedoch mit

do
...
loop while t

statt der äußeren for/next-Schleife. Es läuft halt so lange, wie es Überlappungen gibt.

m<>n innerhalb von if right(i(m),j)=left(i(n),j) and j>t and m<>n, dadurch spare ich mir ein weiteres "if", "then" und "end if".

So wird man nebenher noch diese lästigen Abfragen los...

Markus Oestreicher

Diese Lösung ist anders und zeigt uns Golf wie es sich gehört - knapp, originell und funktional. Die vorbildliche Erklärung folgt den in den Code eingefügten Ziffern.

So... Platz 3 meldet sich auch zu Wort.

<%
(1)
set b=application
a=b("input")
c=ubound(a)

(2)
p=9
while p
 m=1
(3)	for i=0to c
 for j=0to c
  s=a(j)
(4)		if right(a(i),p)=left(s,p)<(i=j)<(s=x)then 
   a(i)=a(i)&mid(s,p+1)
   a(j)=x
(5)			m=0
  end if
 next
 next
(6)	p=p-m
wend
b("output")=join(a,x)
%>

(1) Das traditionelle "must have" (Siehe dazu frühere Tee Off! Artikel)
(2) Ich habe eine Variable p eingeführt. Geprüft werden jeweils p-fache Übereinstimmungen. Ich beginne bei 9 und zähle Stück für Stück herunter.
(3) Die beiden for-Schleifen testen alle Kombinationen durch. An dieser Stelle hatte ich lange mit einem Konstrukt von div/modulo gebastelt, die for/for Schleife war aber letztlich am kürzesten.
(4) Traumhaft... Dieses Konstrukt nutzt die Tatsache aus, daß ein Vergleich (x=y) entweder 0 (false) oder (-1) true liefert. So kann ich mit größer/kleiner die UND Verknüpfung herstellen. Früher stand dort ein (s<>x)and(i<>j)and right(t,p)=left(s,p)
Entwicklungsdauer: verdammt lange, Nutzwert: 3 Bytes ;-)
Der Aufwand kommt daher, weil ich keine leeren Strings miteinander vergleichen darf (s<>x, x undefiniert, spart 1 Byte) bzw. weil ich nicht die selben Positionen miteinander vergleichen darf. (i<>j)
(5) Falls ich zwei Elemente verschmelzen konnte, setze ich m=0 und erzwinge einen erneuten Durchlauf.
(6) Konnte ich nichts ersetzen, gehts weiter mit allen (p-1) fachen Übereinstimmungen. Falls etwas ersetzt werden konnte, ist m hier 0 und die Schleife startet mit dem selben p erneut.
Der Ansatz ist in dieser Form relativ sauber. Leider haben mich auf den letzten Metern ein bischen die Ideen verlassen ;-)

Kopf hoch - beim nächsten Turnier wirds wieder!

Michele Marsching

Die Lösungen werden zwar kürzer je mehr wir uns der Spitze nähern, die Erklärungen aber nicht. Auch hier sind die wichtigsten Schritte nummeriert. Michele hat auch eine sehenswerte Lösung gefunden, die der des Siegers ähnelt, aber doch unterschiedlich ist. Jeder Golfer hat seinen persönlichen Stil. Seht selbst:

Dann wollen wir mal

<%SET a=Application
b=a("input")
FOR L=99TO 1STEP-1 #1
c=UBOUND(b)
FOR z=0TO c #2
FOR y=0TO c
e=b(y)
f=b(z)
IF LEFT(f,L)=RIGHT(e,L)THEN
b(z)=w:b(y)=e&MID(f,L+1):a("output")=join(b,w)END IF #3
NEXT
NEXT
NEXT%>

Nachdem ich zuerst die Übereinstimmung in einem zweidimensionalen Array gespeichert hatte, kam mir irgendwann die Idee, wie bei Johann wohl auch...

Beispiel ALLEK KUEHE HETR TRINKEN
#1 Ich vergleiche von allen Strings Teile der Länge L
#2 Ich gehe 2x durch das Array durch
#3 Finde ich eine Übereinstimmung in den verglichenen Teilen (kueHE - #HEtr), merke ich mir das erste Fragment (f=b(z)), lösche den Wert an der Stelle im Array (b(z)=w) und füge das erste Fragment und den fehlenden Rest des zweiten Fragmentes zusammen und speichere ihn dort, wo das zweite Fragment im Array war. Das neue Array wäre also ALLEK* *KUEHETR*TRINKEN

Mit dem FOR L=-99TO-1 von Johann wäre ich auf 197/196 (wenn 9 statt 99) Bytes gekommen. Beim nächsten Mal fällt mir da auch wieder was vom Auge,... ;)

P.S.: Nachdem ich mit Markus auf einer Stufe war, glaube ich, daß er das selbe hatte wie ich, aber die Zeile 8 bei ihm noch IF e<>""AND z<>y AND LEFT(b(z),L)=RIGHT(e,L)THEN b(y)=e&MID(b(z),L+1):b(z)=w:a("output")=b(y)END IF heißt... fragt mich nicht, wie ich darauf gekommen bin, das eine andere Art, sich den Wert zu merken die Abfragen nicht mehr braucht ;)

P.S.2: Endlich mal Silber *smile*

Bewundernswert. Und nun auf zum Sieger mit seinen unglaublichen 192 Schlägen.

Johann Engbers

Die bisherigen Lösungen waren ja alle mehr oder weniger 'gierig' - d.h. sie suchten nach den größten Überlappungen. Johann ging einen anderen Weg, ähnlich wie Michele und doch anders:

Hallo Golfer, hier dann mein Code:

<%set b=application
h=b("input")
p=ubound(h)
for c=-9to-1
for l=0to p
for i=0to p
if l<>i and right(h(l),-c)=left(h(i),-c)then
h(i)=h(l)&mid(h(i),1-c):h(l)=l:b("output")=h(i)
next:next:next%>

Meine Schleifen funktionieren ein wenig anders, ich suche nicht die größte Überlappung, sondern teste von 9 nach 1 runter (bißchen gepfuscht, 99 wäre besser gewesen) ob es eine solche Überlappung gibt. Dann werden diese Elemente verschmolzen. for c=-9to-1 statt for c=9 to 1 step -1 l<>i brauche ich, damit kein Element mit sich selbst verglichen wird. Ich habe zuerst das verschmolzene Element im Array auf "" gesetzt, brauchte dann aber eine zusätzliche Abfrage. Daher habe ich zum löschen einfach in das i-te Arrayfeld die Zahl i geschrieben (h(l)=l), so stören die gelöschten Werte nicht mehr. Da das Genom zum Schluß ein Ganzes ist, muß es in dem Feld mit der letzten Verschmelzung stehen, daher b("output")=h(i). Spart das Join.

Bravo, die Handhabung der gelöschten Felder ist genial. Ein verdienter erster Platz!

Schlußbemerkung

Bei ASP Golf lernt man immer wieder dazu. Selbst nach all den Turnieren die ich schon als Schiedsrichter betreut habe finde ich doch jedesmal wieder Code der mich staunen macht oder mir Tränen in die Augen treibt. Was wäre das Leben ohne Golf...

Verwandte Artikel

3. Loch - Dr. Evils Qualitätskontrolle
Minigolf - 99 Bottles of Beer
Tee Off - Das erste ASP Golf Turnier
Tee Off! Die Zweite
Tee Off! Zahlen, Wörter, Zahlwörter

Links zu anderen Sites

Leaderboard Loch 7

Wenn Sie jetzt Fragen haben...

Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten.

Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.

 

Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.

Bewerten Sie diesen Artikel
 Sehr gut   Nicht genügend  
   1  2  3  4  5  
 

  
   Für Ausdruck optimierte Seite

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.