Elmaları sırala!


11

Sorun

Üst üste dizilmiş 7 kova düşünün. Her kova en fazla 2 elma içerebilir. 1 ile 13 arasında etiketlenmiş 13 elma vardır. 7 kova arasında dağıtılır. Örneğin,

{5,4}, {8,10}, {2,9}, {13,3}, {11,7}, {6,0}, {12,1}

Burada 0 boş alanı temsil eder. Elmaların her bir kova içinde görünme sırası uygun değildir (örneğin, {5,4}, {4,5} 'e eşdeğerdir).

Başka bir elma için hedef kovada yer olması koşuluyla, herhangi bir elmayı bir kovadan bitişik bir kovaya taşıyabilirsiniz. Her hareket, taşımak istediğiniz elmanın sayısı ile tanımlanır (bu açıktır, çünkü sadece bir boş alan vardır). Örneğin, hareketin uygulanması

7

Yukarıdaki düzenlemeye

{5,4}, {8,10}, {2,9}, {13,3}, {11,0}, {6,7}, {12,1}

Amaç

STDIN'den bir düzenleme okuyan ve aşağıdaki düzenlemeye ayıran bir program yazın

{1,2}, {3,4}, {5,6}, {7,8}, {9,10}, {11,12}, {13,0}

mümkün olduğunca az hamle kullanarak. Yine, elmaların her bir kova içinde ortaya çıkma sırası ilgili değildir. Kovaların sırası önemlidir. Virgüllerle ayrılmış her bir düzenlemeyi sıralamak için kullanılan hareketlerin çıktısını almalıdır. Örneğin,

13, 7, 6, ...

Puanınız, aşağıdaki düzenlemeleri çözmek için gereken hamle sayısına eşittir:

{8, 2}, {11, 13}, {3, 12}, {6, 10}, {4, 0}, {1, 7}, {9, 5}
{3, 1}, {6, 9}, {7, 8}, {2, 11}, {10, 5}, {13, 4}, {12, 0}
{0, 2}, {4, 13}, {1, 10}, {11, 6}, {7, 12}, {8, 5}, {9, 3}
{6, 9}, {2, 10}, {7, 4}, {1, 8}, {12, 0}, {5, 11}, {3, 13}
{4, 5}, {10, 3}, {6, 9}, {8, 13}, {0, 2}, {1, 7}, {12, 11}
{4, 2}, {10, 5}, {0, 7}, {9, 8}, {3, 13}, {1, 11}, {6, 12}
{9, 3}, {5, 4}, {0, 6}, {1, 7}, {12, 11}, {10, 2}, {8, 13}
{3, 4}, {10, 9}, {8, 12}, {2, 6}, {5, 1}, {11, 13}, {7, 0}
{10, 0}, {12, 2}, {3, 5}, {9, 11}, {1, 13}, {4, 8}, {7, 6}
{6, 1}, {3, 5}, {11, 12}, {2, 10}, {7, 4}, {13, 8}, {0, 9}

Evet, bu düzenlemelerin her birinin bir çözümü var.

kurallar

  • Çözümünüz, hareket başına kova sayısında polinom zamanda çalışmalıdır. Mesele akıllı buluşsal yöntemler kullanmaktır.
  • Tüm algoritmalar deterministik olmalıdır.
  • Beraberlik durumunda, en kısa bayt sayısı kazanır.

2
Bir elmayı taşıyabileceğiniz tek bir alan olduğunda hedefi belirtmenin anlamı nedir?
John Dvorak

Kaba kuvvet çözümüm makul bir sürede çalışırsa ne olur? Sadece 700M durumları vardır - dakikalar içinde kolayca numaralandırılabilir. "Makul bir süre" tanımlayın.
John Dvorak

@JanDvorak "Ne anlamı var" - iyi çağrı. Bu benim başıma gelmemişti. Ben burada çözüm kaba kaba kuvvet için gerekli zaman miktarından daha az olması makul olarak tanımlamak ;)
Orby

"Makul" tanımınız önce kaba kuvvet çözümünü, sonra daha hızlı olan her şeyi uygulamamız gerektiği anlamına mı geliyor?
John Dvorak

Kovanın son sırası önemli mi?
AMK

Yanıtlar:


4

Puan: 448

Benim fikrim onları 1 ile başlayarak arka arkaya sıralamaktır. Bu bize alanı önceki / sonraki sepete taşımak istediğimizde, oradaki iki elmadan hangisini hareket ettirmemiz gerektiğini bildiğimiz güzel bir özellik verir. min. İşte test dökümü:

#1: 62     #6: 40
#2: 32     #7: 38
#3: 46     #8: 50
#4: 50     #9: 54
#5: 40    #10: 36

Total score: 448 moves

Kod çok daha fazla golf edilebilir, ancak kodun daha iyi kalitesi ek cevapları motive edecektir.

C ++ (501 bayt)

#include <cstdio>
#define S(a,b) a=a^b,b=a^b,a=a^b;
int n=14,a[14],i,j,c,g,p,q;
int l(int x){for(j=0;j<n;++j)if(a[j]==x)return j;}
int sw(int d){
    p=l(0);q=p+d;
    if(a[q]*d>a[q^1]*d)q^=1;
    printf("%d,", a[q]);
    S(a[q],a[p])
}
int main(){
    for(;j<n;scanf("%d", a+j),j++);
    for(;++i<n;){
        c=l(i)/2;g=(i-1)/2;
        if(c-g){
            while(l(0)/2+1<c)sw(2);
            while(l(0)/2>=c)sw(-2);
            while(l(i)/2>g){sw(2);if(l(i)/2>g){sw(-2);sw(-2);}}
        }
    }
}

Diğer iyileştirmeler C'ye geçmek ve büyük değerlerden aşağı doğru başlayarak skoru düşürmeye çalışmak olabilir (ve sonunda her iki çözümü de birleştirir).


1
Kodunuzun bir alt dizesi zaten bir C programı oluşturur. Özellikle, ilk satırı silerek C'de çalışabilir.
feersum

@feersum Haklısın. Başlangıçta, daha fazla C ++ özel kodu vardı, ama ondan sonra C'ye geçiş ile, ondan kurtuldum gibi görünüyor.
yasen

Doğrulamaya çalışanlara daha açık hale getirmek için çözümünüzdeki giriş biçimini değiştirdiğinizi belirtebilir misiniz?
Orby

2

Cı, 426 448

Bu, elmaları yasen'in yöntemine benzer şekilde her seferinde 1'den 13'e kadar sıralar , ancak daha büyük bir sayıyı yukarı veya daha küçük bir sayıyı aşağı hareket ettirme fırsatı olduğunda, bunu alacaktır. Ne yazık ki, bu sadece ilk test problemindeki performansı arttırır, ancak küçük bir gelişme. Test problemlerini çalıştırırken bir hata yaptım. Görünüşe göre yasen'in yöntemini yeniden uyguladım.

#1: 62    #6: 40
#2: 32    #7: 38
#3: 46    #8: 50
#4: 50    #9: 54
#5: 40    #10: 36

Parantez veya virgül olmadan girdi alır, örn.

8 2 11 13 3 12 6 10 4 0 1 7 9 5

İşte birkaç gereksiz satırsonu sayma 423 bayt gelen golf kodu (muhtemelen daha fazla golf olabilir, ama bu skorun dayak bekliyoruz):

#define N 7
#define F(x,y) for(y=0;y<N*2;y++)if(A[y]==x)break;
#define S(x,y) x=x^y,y=x^y,x=x^y;
#define C(x,y) ((A[x*2]==y)||(A[x*2+1]==y))
A[N*2],i,j,d,t,b,a,n,s,v,u,w,g;main(){for(;i<N*2;i++)scanf("%d",A+i);g=1;while
(!v){F(0,i);b=i/2;F(g,u);w=u/2;d=b<w?1:-1;n=(b+d)*2;a=(b+d)*2+1;if(A[n]>A[a])
S(n,a);t=d-1?a:n;printf("%d,",A[t]);S(A[i],A[t]);while(C((g-1)/2,g))g++;v=1;for
(j=0;j<N*2;j++)if(!C(j/2,(j+1)%(N*2)))v=0;}}

Ve skoru yazdıran ungolfed kodu:

#include <stdio.h>
#include <stdlib.h>

#define N 7

int apples[N*2];

int find(int apple)
{
    int i;
    for (i = 0; i < N*2; i++) {
        if (apples[i] == apple)
            return i;
    }    
}

void swap(int i, int j)
{
    int temp;
    temp = apples[i];
    apples[i] = apples[j];
    apples[j] = temp;
}

int contains(int bucket, int apple)
{
    if ((apples[bucket * 2] == apple) || (apples[bucket * 2 + 1] == apple))
        return 1;
    return 0;
}

int is_solved()
{
    int i, j;
    for (i = 0; i < N * 2; i++) {
        j = (i + 1) % (N * 2);
        if (!contains(i / 2, j))
            return 0;
    }
    return 1;
}

int main()
{
    int i, j, dir, bucket, max, min, score;
    int target_i, target_bucket, target;

    /* Read the arrangement */
    for (i = 0; i < N*2; i++) {
        scanf("%d ", apples + i);
    }

    target = 1;
    while (1) {

        i = find(0);
        bucket = i / 2;
        target_i = find(target);
        target_bucket = target_i / 2;

        /* Change the direction of the sort if neccesary */
        if (bucket < target_bucket) dir = 1;
        else dir = -1;

        /* Find the biggest and smallest apple in the next bucket */
        if (apples[(bucket + dir) * 2] < apples[(bucket + dir) * 2 + 1]) {
            min = (bucket + dir) * 2;
            max = (bucket + dir) * 2 + 1;
        } else {
            min = (bucket + dir) * 2 + 1;
            max = (bucket + dir) * 2;
        }

        /* If we're going right, move the smallest apple. Otherwise move the
           biggest apple */
        if (dir == 1) {
            printf("%d, ", apples[min]);
            swap(i, min);
            score++;
        } else {
            printf("%d, ", apples[max]);
            swap(i, max);
            score++;
        }

        /* Find the next apple to sort */
        while (contains((target - 1) / 2, target))
            target++;

        /* If we've solved it then quit */
        if (is_solved())
            break;
    }
    printf("\n");
    printf("%d\n", score);
}

2

Python 3-121

Bu, bir çözüm bulana kadar artan derinlikte önce derinlik araması gerçekleştirir. Ziyaret edilen durumları saklamak için bir sözlük kullanır, böylece daha yüksek bir derinlik penceresi olmadığı sürece tekrar ziyaret etmez. Hangi durumların kontrol edileceğine karar verirken, yanlış yerleştirilmiş elemanların sayısını sezgisel olarak kullanır ve yalnızca mümkün olan en iyi durumları ziyaret eder. Kovalarındaki elemanların sırası önemli olmadığından, her zaman kovalar içinde bir sıralamayı koruduğunu unutmayın. Bu, bir elemanın yanlış yerleştirilip yerleştirilmediğini kontrol etmeyi kolaylaştırır.

Giriş, bir int dizisidir ve ilk int, kova sayısıdır.

Örneğin, # 8 için (bu makinemde çalışmak çok uzun sürüyor, diğerleri saniyeler içinde bitiyor):

c:\python33\python.exe apples.py 7 3 4 10 9 8 12 2 6 5 1 11 13 7 0

Test setindeki sonuçlar şunlardır: # 1: 12, # 2: 12, # 3: 12, # 4: 12, # 5: 11, # 6: 11, # 7: 10, # 8: 14, # 9: 13, # 10: 14

İşte kod:

import sys    

BUCKETS = int(sys.argv[1])    

# cleans a state up so it is in order
def compressState(someState):
  for i in range(BUCKETS):
    if(someState[2*i] > someState[2*i + 1]):
      temp = someState[2*i]
      someState[2*i] = someState[2*i + 1]
      someState[2*i + 1] = temp
  return someState    

state = compressState([int(x) for x in sys.argv[2:]])
print('Starting to solve', state)
WINNINGSTATE = [x for x in range(1, BUCKETS*2 - 1)]
WINNINGSTATE.append(0)
WINNINGSTATE.append(BUCKETS*2 - 1)
maxDepth = 1
winningMoves = []
triedStates = {}    

# does a depth-first search
def doSearch(curState, depthLimit):
  if(curState == WINNINGSTATE):
    return True
  if(depthLimit == 0):
    return False
  myMoves = getMoves(curState)
  statesToVisit = []
  for move in myMoves:
    newState = applyMove(curState, move)
    tns = tuple(newState)
    # do not visit a state again unless it is at a higher depth (more chances to win from it)
    if(not ((tns in triedStates) and (triedStates[tns] >= depthLimit))):
      triedStates[tns] = depthLimit
      statesToVisit.append((move, newState[:], stateScore(newState)))
  statesToVisit.sort(key=lambda stateAndScore: stateAndScore[2])
  for stv in statesToVisit:
    if(stv[2] > statesToVisit[0][2]):
      continue
    if(doSearch(stv[1], depthLimit - 1)):
      winningMoves.insert(0, stv[0])
      return True
  return False    

# gets the moves you can make from a given state
def getMoves(someState):
  # the only not-allowed moves involve the bucket with the 0
  allowedMoves = []
  for i in range(BUCKETS):
    if((someState[2*i] != 0) and (someState[2*i + 1] != 0)):
      allowedMoves.append(someState[2*i])
      allowedMoves.append(someState[2*i + 1])
  return allowedMoves    

# applies a move to a given state, returns a fresh copy of the new state
def applyMove(someState, aMove):
  newState = someState[:]
  for i in range(BUCKETS*2):
    if(newState[i] == 0):
      zIndex = i
    if(newState[i] == aMove):
      mIndex = i
  if(mIndex % 2 == 0):
    newState[mIndex] = 0
  else:
    newState[mIndex] = newState[mIndex-1]
    newState[mIndex-1] = 0
  newState[zIndex] = aMove
  if((zIndex % 2 == 0) and (newState[zIndex] > newState[zIndex+1])):
    newState[zIndex] = newState[zIndex+1]
    newState[zIndex+1] = aMove
  return newState    

# a heuristic for how far this state is from being sorted
def stateScore(someState):
  return sum([1 if someState[i] != WINNINGSTATE[i] else 0 for i in range(BUCKETS*2)])    

# go!
while(True):
  triedStates[tuple(state)] = maxDepth
  print('Trying depth', maxDepth)
  if(doSearch(state, maxDepth)):
    print('winning moves are: ', winningMoves)
    break
  maxDepth += 1

Bunu en iyi çözümleri görmek yararlı olduğu için destekledim, ancak bunun sorunun gerektirdiği gibi hareket başına kova sayısında polinom zamanda çalışmadığına dikkat edin. (Genel olarak) optimal bir çözüm üreten herhangi bir algoritmanın polinom zamanında çalışabileceğine inanmıyorum.
Orby

İlk test problemi için programınız geçerli bir çözüm olmayan 10, 8, 1, 12, 6, 7, 11, 3, 5, 13, 4, 9 üretir. Bence soruyu yanlış anlamış olabilirsiniz. Soru, "Herhangi bir elmayı bir kovadan bitişik bir kovaya taşıyabilirsiniz" ifadesine, yani sağındaki veya solundaki kovaya (rastgele bir kova değil) dikkat edin.
Orby

Ah, bitişiklik kısıtlamasını tamamen kaçırdım! Bunu gönderdikten sonra, çalışma süresi kısıtlamasının da ihlal edildiğinden şüpheleniyordum. Yazarken% 100 emin değildim, çünkü tekrarlanan durumlardan kaçınmanın dinamik programlama elemanı beni şaşırttı. Bu, iki açıdan başarısız olsa da, yukarı oy için teşekkür ederiz; Bu eğlenceli bir bulmaca ve daha iyi, geçerli bir cevap bulup bulamayacağımı göreceğim.
RT
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.