Phán quyết từ tiếng Latin


8

Vì tôi không thể tập trung vào bất kỳ tác vụ nào trong hơn 5 giây, tôi thường thấy mình chia các từ thành một chuỗi con, mỗi chuỗi có độ dài khác nhau và không chứa bất kỳ ký tự lặp lại nào. Ví dụ: từ "pasta" có thể bị chia nhỏ trong "quá khứ" & "a", "pas" & "ta" hoặc "pa" & "sta" và bạn có được hình ảnh.

Tuy nhiên, vì việc nhớ tất cả các kết hợp là khó khăn, tôi thường chỉ chọn một kết hợp và tôi thích chọn kết hợp đẹp nhất. Chúng tôi xem xét cách tốt nhất để có "điểm" thấp nhất. Nhiệm vụ của bạn sẽ là, cho một từ, để in điểm của nó, đưa ra các quy tắc phức tạp sau đây.

Chấm điểm

Mô tả cách ghi một từ:

  • Một từ là một chuỗi các ký tự Latinh, chữ hoa nên được thay thế bằng 2 chữ cái viết thường (vì vậy "Hộp" trở thành "bbox")

  • Phân đoạn là một chuỗi con liền kề (nghiêm ngặt) của một từ và không được chứa bất kỳ ký tự nào hai lần ("her", "re", "h" là tất cả các phân đoạn hợp lệ của "Ở đây" ("hhere"), nhưng "hh" và "ere" thì không)

  • Phân đoạn là một tập hợp các phân đoạn có độ dài khác nhau, khi được nối, tạo thành từ gốc ("tre" và "e" tạo thành "cây") và không thể phân đoạn thêm trong phân khúc (tức là "ba" có một phân đoạn duy nhất phân đoạn, "ba"; và "alp" & "hjack" không phải là phân đoạn hợp lệ của "bảng chữ cái", bởi vì một trong hai phân đoạn này có thể được phân đoạn thêm (ví dụ: "a" & "lp" & "hjack", hiện tại một phân đoạn hợp lệ ("hjack" không thể được phân đoạn mà không tạo thành một phân đoạn có độ dài 2 hoặc 1))).

  • Điểm của một phân đoạn là tổng số điểm của từng ký tự riêng biệt xuất hiện trong từ gốc (một khi chữ viết hoa đã được thay thế)

  • Điểm của các nhân vật được giải thích dưới đây

  • Điểm của một từ là điểm của phân đoạn đẹp nhất có thể của nó (với điểm thấp nhất)

Nếu không có phân đoạn hợp lệ tồn tại cho một từ (ví dụ: "Brass" ("bbrass"), không thể phân đoạn vì "b" đầu tiên và "s" cuối cùng sẽ phải nằm trong phân khúc riêng của họ, điều đó sẽ dẫn đến trong hai phân đoạn có cùng độ dài), sau đó bạn nên xuất văn bản "ác", nếu không, bạn nên xuất điểm của từ.

Điểm nhân vật

Cách tính điểm của các ký tự dựa trên số lần nhân vật xuất hiện và trọng số của các phân đoạn xuất hiện. Trọng số của các phân đoạn phụ thuộc vào độ dài của phân đoạn và bội số chung thấp nhất của tất cả các phân đoạn trong sự phân chia.

segment weighting = lowest common multiple of lengths segments / length of segment

Hãy xem xét từ "ô liu", có thể được phân đoạn thành "ol" & "ive" và được hiển thị dưới dạng 2 hộp có cùng diện tích, một trong số "ol" có trọng lượng 3 và một "ive" có trọng lượng 2 (LCM của 6).

ol
ol ive
ol ive

Điều này có nghĩa là để mô tả hai hộp, một hộp được làm từ 3 "ol" và một hộp được làm từ 2 "ive". Thay vào đó, nó có thể là "o" & "sống" (LCM 4)

o
o
o
o live

Điểm của mỗi ký tự sau đó là tổng trọng số của các phân đoạn xuất hiện, nhân với số lần xuất hiện sau khi thay thế chữ hoa (vì vậy nếu xuất hiện hai lần, bạn sẽ bị tính phí gấp đôi cho mỗi lần bạn phải nói ).

character score = character count * sum(segment weights in which character appears)

Ví dụ chấm điểm

Chúng tôi lấy từ "ngã", nó chỉ có thể được phân thành "fal" và "l". Bội số chung thấp nhất của 3 và 1 là 3, vì vậy "fal" có trọng số 1 và "l" có trọng số 3.

    l
    l
fal l

Đi qua từng nhân vật ...

  • "f" xuất hiện một lần và nằm trong phân đoạn "fal" với trọng số 1, do đó, có điểm 1 * 1 = 1

  • "a" cũng chỉ xuất hiện một lần, có tổng trọng số là 1, vì vậy có điểm 1 * 1 = 1

  • "l" xuất hiện hai lần và xuất hiện trong "fal" (trọng lượng 1) và "l" (trọng lượng 3), do đó, có điểm 2 * (1 + 3) = 8

Tổng của những điều này là 10 (điểm của phân khúc và của từ, vì đây là phân khúc đẹp nhất). Đây là định dạng tương tự như các ví dụ dưới đây:

fall = fal l
2*1 [fa] + 2*(1+3) [ll] = 10

Ví dụ ghi bàn

Những ví dụ về ghi điểm có thể hoặc không thể giúp:

class -> clas s
3*1 [cla] + 2*(4+1) [ss] = 13

fish -> fis h
3*1 [fis] + 1*3 [h] = 6

eye -> e ye
1*1 [y] + 2*(1+2) [ee] = 7

treasure -> treas u re
3*2 [tas] + 2*2*(2+5) [rree] + 1*10 [u] = 44

Wolf -> w wolf
3*1 [olf] + 2*(1+4) = 13

book
evil

"Cuốn sách" là một từ xấu xa, vì vậy không có điểm.

Lưu ý rằng "kho báu" có thể được phân đoạn theo một số cách, nhưng phân đoạn cho thấy lợi ích từ việc có các chữ cái thường xuyên hơn ("r" và "e") trong các phân đoạn dài hơn, vì vậy chúng không có trọng lượng như nhau. Phân đoạn "t" & "re" & "asure" sẽ cho kết quả tương tự, trong khi "treas" & "ur" & "e" sẽ bị ảnh hưởng, với "e" có điểm 2 * (1 + 10 + 2 ) = 24 trên chính nó. Quan sát này thực sự là tinh thần của toàn bộ bài tập. Một ví dụ về điểm "kho báu" không chính xác (không chính xác vì nó không xuất phát từ điểm của phân khúc đẹp nhất (có điểm thấp nhất)):

treasure = treas ur e
3*2 [tas] + 2*(2+5) [rr] + 1*5 [u] + 2*[2+10] = 49

Đầu vào

Một chuỗi duy nhất chỉ chứa các ký tự Latin của một trong hai trường hợp ("ngựa", "Ngựa" và "hOrSe" đều là các đầu vào hợp lệ) có thể được chấp nhận bởi STDIN, đối số dòng lệnh, đối số hàm hoặc nếu không thì ngôn ngữ của bạn sự lựa chọn không hỗ trợ bất kỳ điều nào đã nói ở trên.

Đầu ra

Bạn phải xuất điểm của từ, là một số nguyên dương duy nhất lớn hơn 0 hoặc "ác" nếu không có phân đoạn nào tồn tại. Đầu ra phải là STDOUT hoặc đối số trả về của hàm, trừ khi ngôn ngữ bạn chọn không hỗ trợ cả hai thứ này, trong trường hợp đó làm một cái gì đó thể thao.

Ví dụ

Tôi không mong đợi bạn in tất cả những thứ này, tất cả những gì tôi muốn là điểm của từ hoặc đầu ra "ác", ví dụ (đầu vào tiếp theo là đầu ra)

eye
7

Eel
evil

a
1

Establishments
595

antidisestablishmentarianism
8557

Tôi không quan tâm đến hiệu suất, nếu bạn có thể ghi được bất kỳ từ 15 bản nào (sau khi thay thế chữ hoa) trong một phút trên một máy hợp lý (mơ hồ còn mơ hồ), điều đó đủ tốt cho tôi.

Đây là môn đánh gôn, có thể là đoạn mã ngắn nhất sẽ thắng.

Cảm ơn PeterTaylor, MartinBüttner và SP3000 vì sự giúp đỡ của họ với thử thách này


4
Nếu bạn không thể tập trung vào bất kỳ nhiệm vụ nào dài hơn 5 giây, viết ra thử thách này chắc chắn sẽ đưa bạn mãi mãi!
Alex A.

Câu trả lời:


5

Toán học, 373 byte

If[l=Length;a=Accumulate[l/@#]&;u=Unequal;e=Select;{}==(m=(g=#;Tr[#2Flatten[ConstantArray[#,LCM@@l/@g/l@#]&/@g]~Count~#&@@@Tally@c])&/@e[p=e[c~Internal`PartitionRagged~#&/@Join@@Permutations/@IntegerPartitions[l[c=Characters[s=StringReplace[#,c:"A"~CharacterRange~"Z":>(d=ToLowerCase@c)<>d]]]],u@@l/@#&&And@@u@@@#&],FreeQ[p,l_List/;#!=l&&SubsetQ[a@l,a@#]]&]),"evil",Min@m]&

Cái này khá dài ... và cũng khá ngây thơ. Nó định nghĩa một hàm không tên lấy chuỗi và trả về điểm số. Mất khoảng 1 giây để xử lý "Establishments", vì vậy nó cũng trong thời gian giới hạn. Tôi đã có một phiên bản ngắn hơn một chút sử dụng Combinatorica`SetPartitions, nhưng nó đã mất một phút cho "Establishme".

Đây là một phiên bản có khoảng trắng:

If[
  l = Length;
  a = Accumulate[l /@ #] &;
  u = Unequal;
  e = Select;
  {} == (
    m = (
      g = #;
      Tr[
        #2 Flatten[
          ConstantArray[
            #, 
            LCM @@ l /@ g/l@#
          ] & /@ g
        ]~Count~# & @@@ Tally@c
      ]
    ) & /@ e[
      p = e[
        c~Internal`PartitionRagged~# & /@ Join @@ Permutations /@ IntegerPartitions[
          l[
            c = Characters[
              s = StringReplace[
                #, 
                c : "A"~CharacterRange~"Z" :> (d = ToLowerCase@c) <> d
              ]
            ]
          ]
        ], 
        u @@ l /@ # && And @@ u @@@ # &
      ], 
      FreeQ[p, l_List /; # != l && SubsetQ[a@l, a@#]] &
    ]
  ),
  "evil",
  Min@m
] &

Tôi có thể thêm một lời giải thích chi tiết hơn sau. Mã này sử dụng giải pháp thứ hai từ câu trả lời này để có được tất cả các phân vùng và giải pháp này để đảm bảo tất cả chúng đều được phân chia tối đa.


2

Java 8, 1510 1485 byte

Đây là cách quá dài. Kết hợp không bao giờ dễ dàng trong java. Nó chắc chắn có thể được rút ngắn khá nhiều. Gọi với a(string). Điều này sử dụng một thuật toán bộ nhớ và thời gian theo cấp số nhân; vì vậy đừng mong đợi nó hoạt động cho đầu vào dài. Phải mất khoảng nửa giây để xử lý Establishments. Nó gặp sự cố với lỗi hết bộ nhớ cho antidisestablishmentarianism.

import java.util.*;import java.util.stream.*;void a(String a){a=a.replaceAll("\\p{Upper}","$0$0").toLowerCase();List<List<String>>b=b(a),c;b.removeIf(d->d.stream().anyMatch(e->e.matches(".*(.).*\\1.*")));b.removeIf(d->{for(String e:d)for(String f:d)if(e!=f&e.length()==f.length())return 1>0;return 1<0;});c=new ArrayList(b);for(List<String>d:b)for(List<String>e:b){if(d==e)continue;int f=0,g=0;List h=new ArrayList(),i=new ArrayList();for(String j:d)h.add(f+=j.length());for(String k:e)i.add(g+=k.length());if(i.containsAll(h))c.remove(d);else if(h.containsAll(i))c.remove(e);}b=c;int d=-1;for(List e:b)d=d<0?c(e):Math.min(c(e),d);System.out.println(d<0?"evil":d);}int c(List<String>a){List<Integer>b=a.stream().map(c->c.length()).collect(Collectors.toList()),d;int e=d(b.toArray(new Integer[0])),f=0,g=0,h;d=b.stream().map(A->e/A).collect(Collectors.toList());Map<Character,Integer>i=new HashMap(),j=new HashMap();for(;g<a.size();g++){h=d.get(g);String k=a.get(g);for(char l:k.toCharArray()){i.put(l,i.getOrDefault(l,0)+1);j.put(l,j.getOrDefault(l,0)+h);}}for(char k:i.keySet())f+=i.get(k)*j.get(k);return f;}int d(Integer...a){int b=a.length,c,d,e;if(b<2)return a[0];if(b>2)return d(a[b-1],d(Arrays.copyOf(a,b-1)));c=a[0];d=a[1];for(;d>0;d=c%d,c=e)e=d;return a[0]*a[1]/c;}List b(String a){List<List>b=new ArrayList(),c;for(int i=0;++i<a.length();b.addAll(c)){String d=a.substring(0,i),e=a.substring(i);c=b(e);for(List f:c)f.add(0,d);}b.add(new ArrayList(Arrays.asList(a)));return b;}

Thử ở đây

Ấn định với lời giải thích:

void a(String a){
    a = a.replaceAll("\\p{Upper}", "$0$0").toLowerCase();                //Replace all uppercase letters with two lowercase letters

    List<List<String>> b = b(a), c;                                      //Generate partitions
    b.removeIf(d -> d.stream().anyMatch(e -> e.matches(".*(.).*\\1.*")));//Remove partitions that contains duplicate letters

    b.removeIf(d -> {                                                    //Remove partitions that have equal length parts
        for (String e : d)
            for (String f : d)
                if (e != f & e.length() == f.length())
                    return 1 > 0;
        return 1 < 0;
    });

    c = new ArrayList(b);                                                //Remove partitions that can be partitioned further
    for (List<String> d : b)                                             //Uses Martin's technique
        for (List<String> e : b){
            if (d == e)
                continue;
            int f = 0, g = 0;
            List h = new ArrayList(), i = new ArrayList();
            for (String j : d)
                h.add(f += j.length());
            for (String k : e)
                i.add(g += k.length());
            if (i.containsAll(h))
                c.remove(d);
            else if (h.containsAll(i))
                c.remove(e);
        }

    b = c;

    int d = -1;
    for (List e : b)
        d = d < 0 ? c(e) : Math.min(c(e), d);                            //Find nicest partition

    System.out.println(d < 0 ? "evil" : d);
}

int c(List<String> a) {                                                  //Grade a partition
    List<Integer> b = a.stream().map(c->c.length()).collect(Collectors.toList()), d; //Map to length of parts

    int e = d(b.toArray(new Integer[0])), f = 0, g = 0, h;

    d = b.stream().map(A -> e / A).collect(Collectors.toList());         //Figure out the weight of each part

    Map<Character, Integer> i = new HashMap(), j = new HashMap();

    for (; g < a.size(); g++){                                           //Count instances of each character and
        h = d.get(g);                                                    //weight of each character
        String k = a.get(g);
        for (char l : k.toCharArray()){
            i.put(l, i.getOrDefault(l, 0) + 1);
            j.put(l, j.getOrDefault(l, 0) + h);
        }
    }

    for (char k : i.keySet())
        f += i.get(k) * j.get(k);                                        //Sum cost of each character

    return f;
}

int d(Integer... a) {                                                    //Find lcm
    int b = a.length, c, d, e;
    if (b < 2)
        return a[0];
    if (b > 2)
        return d(a[b - 1], d(Arrays.copyOf(a, b - 1)));
    c = a[0];
    d = a[1];
    for (;d > 0;d = c % d, c = e)
        e = d;
    return a[0] * a[1] / c;
}

List b(String a) {                                                       //Find all partitions of a string
    List<List> b = new ArrayList(), c;                                   //Uses recursion
    for (int i = 0; ++i < a.length();b.addAll(c)){
        String d = a.substring(0, i), e = a.substring(i);
        c = b(e);
        for (List f : c)
            f.add(0, d);
    }
    b.add(new ArrayList(Arrays.asList(a)));
    return b;
}

Điều này cũng lạm dụng tổng quát khá nhiều để giảm số byte. Tôi khá ngạc nhiên khi tôi có thể biên dịch tất cả.

Cảm ơn Ypnypn :)


Wow, thật ấn tượng! Một vài lưu ý khi chơi gôn: Có thêm khoảng trắng với i.put...dòng và vòng lặp while; Tôi nghĩ while(d!=0) có thể được while(d>0); không có nhu cầu new ArrayListcuối cùng kể từ khi Arrays.asListđưa ra một ArrayListdù sao; trong phương thức cuối cùng bạn có thể định nghĩa blà một đơn vị List.
Ypnypn 17/03/2015

@Ypnypn Cảm ơn bạn đã góp ý :) Arrays.asListtrả lại một giá trị không thể thay đổi ArrayList, vì vậy tôi không thể sử dụng nó mà không nhận được OperationNotSupportedException. bcó thể là một danh sách đơn giản, nhưng ccần ở lại a List<List<String>>. Tôi sẽ kiểm tra xem while(d>0)ngày mai có hoạt động không.
TheNumberOne 17/03/2015

2

C # 679 byte

Giải pháp này gần như dựa trên cấu trúc của việc thực hiện thử nghiệm ban đầu của tôi và ban đầu chỉ là một bài viết lại được đánh gôn, nhưng sau đó tôi đã nội tuyến tất cả các chức năng, và bây giờ nó thật kinh khủng. Nó khá nhanh, giải quyết các Cơ sở dưới một giây. Đây là một chương trình hoàn chỉnh lấy từ đầu vào làm một thông số duy nhất của ARGV.

using Q=System.String;class P{static void Main(Q[]A){Q s="";foreach(var c in A[0]){var z=(char)(c|32);if(c<z)s+=z;A[0]=s+=z;}int r=S(A);System.Console.WriteLine(r<1?"evil":""+r);}static int S(Q[]s){int r=0,t,j,k,L=1,Z=s.Length,i=Z,T=0,R=2;for(;i-->0;R=t<1?0:R){t=s[i].Length;k=L;for(j=2;t>1;)if(t%j++<1){t/=--j;if(k%j<1)k/=j;else L*=j;}}foreach(var C in Q.Join("",s))for(i=Z;i-->0;){for(k=s[j=i].Length;j-->0;)R=k==s[j].Length?0:R;j=s[i].IndexOf(C)+1;R=j*R*s[i].IndexOf(C,j)>1?1:R;T+=j>0?L/k:0;}i=R<1?0:Z;for(var U=new Q[Z+1];i-->0;)for(j=s[i].Length;j-->1;r=r<1|((t=S(U))>0&t<r)?t:r)for(U[k=Z]=s[i].Substring(j);k-->0;U[i]=s[i].Substring(0,j))U[k]=s[k];return r<1?R<2?R-1:T:r;}}

Các Mainphương pháp bắt đầu bằng cách tạo ra một bản sao của các đầu vào với vốn thay thế. Sau đó, nó gọi S, "bộ giải", trả về điểm của một phân đoạn nhất định (phân đoạn đầu tiên là với một phân đoạn duy nhất là toàn bộ từ). Sau đó, nó sẽ in "ác" hoặc điểm số, tùy thuộc vào điểm số.

"Bộ giải" ( S) thực hiện tất cả các công cụ thú vị và ban đầu được chia thành 4 phương thức, được cuộn lại với nhau. Nó hoạt động bằng cách trước tiên chấm điểm phân đoạn hiện tại, ghi chú xem nó có hợp lệ không (và điều quan trọng là nó có hợp lệ không, chúng tôi không nên cố gắng phân đoạn tiếp theo (để thực hiện), bỏ qua phần còn lại của tính toán nếu có) . Sau đó, nếu nó không bị bỏ qua, nó sẽ phân tách từng phân đoạn trong phân khúc ở mọi nơi mà nó có thể được phân tách và tìm thấy điểm số tốt nhất trong số tất cả các phân đoạn này (gọi đệ quy S). Cuối cùng, nó sẽ trả về điểm số cao nhất của Phân đoạn cấp dưới, nếu không thì điểm số của chính nó hoặc không hợp lệ nếu phân đoạn của chính nó không hợp lệ.

Mã có ý kiến:

using Q=System.String; // this saves no bytes now

class P
{
    // boring
    static void Main(Q[]A)
    {
        // this can surely be shorter
        // replace capitals
        // I refuse to put this in S (would give us a Q, but we'd have to pay for the Action=null)
        Q s="";

        foreach(var c in A[0])
        {
            var z=(char)(c|32); // ugly
            if(c<z)
                s+=z; // ugly
            A[0]=s+=z; // reuse the array
        }

        int r=S(A); // reuse the array
        System.Console.WriteLine(r<1?"evil":""+r);
    }

    // solve
    static int S(Q[]s) // s is current solution
    {        
        int r=0,t,j,k,
        L=1,Z=s.Length,i=Z,
        T=0, // is score for this solution (segmentation)
        R=2; // R is current return value, as such, 0 -> return -1, 1 -> return 0, 2 -> return T

        // score first
        // factorise stuff, L is LCM
        for(;
            i-->0; // for each segment
            R=t<1?0:R) // segment too short (skip)
        {
            t=s[i].Length;

            k=L; // we cut up k as we cut up c, when we can't cut up k, we need to build up L
            for(j=2;t>1;)
                if(t%j++<1) // j goes into t
                {
                    t/=--j; // cut up t
                    if(k%j<1) // j goes into k
                        k/=j; // cut up k
                    else
                        L*=j; // j does not go into k, build up L
                }
        }

        // recycle i, j, k, (t)

        foreach(var C in Q.Join("",s)) // for each character
            for(i=Z;i-->0;) // for each segment
            {
                for(k=s[j=i].Length;
                    j-->0;) // for all the segments that follow
                    R=k==s[j].Length?0:R; // repeat length (skip)

                j=s[i].IndexOf(C)+1;

                // these both check if this segment contains the char (j > 0)
                R=j*R*s[i].IndexOf(C,j)>1?1:R; // duplicate char (allow)

                T+=j>0?L/k:0; // add on the segment weight
            }

        // R is whether we are invalid or not
        // T is our score

        i=R<1?0:Z; // if segmentation invalid and can't be segmented, skip everything (performance)

        // recycle i, j, k, t
        // first use of r=0

        for(var U=new Q[Z+1];
            i-->0;) // for each segment
            for(j=s[i].Length;
                j-->1; // for each place we can split it
                r=r<1|((t=S(U))>0&t<r)?t:r) // solve where we split thing at i at position j, if this score is better than r, replace r with it
                for(U[k=Z]=s[i].Substring(j); // put second half of s[i] in last position (order doesn't matter)
                    k-->0; // for each char in s[i]
                    U[i]=s[i].Substring(0,j)) // put first half of s[i] in p position
                    U[k]=s[k]; // copy across everything else

        return r<1?R<2?R-1:T:r; // if we didn't find a valid solution more segmented than this, return our score (unless we are invalid, in which case, return R-1), else the score for the more segmentation solution
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.