2016-06-15 1 views
0

오히려 간단한 하위 문제가 발생했을 때 문제를 해결하고있었습니다. 두 문자열 S1S2이 제공된 경우 merge(S1,S2)은 두 문자열 S1S2을 산재 시켜서 얻은 문자열을 나타내며 결과 문자열이 사전식이 최소가되도록 두 문자의 문자 순서를 유지합니다.두 문자열을 병합하고 가장 작은 병합 된 사전 식 문자열

S1 = abad 
S2 = bbde 
merge(S1, S2) = ababbdde 

은 이제, 문자열 양자의 첫 번째 요소부터 욕심 기술을 적용하고 가장 작은 요소를 찾고, 그 결과로 추가함으로써이 문제를 해결하려고. 그러나 곧 이것이 최적의 솔루션으로 이어지지는 않는다는 것을 알게되었습니다. 코드는 다음과 같습니다.

int n = a.size(), m = b.size(); 
int i =0, j=0, k=0; char array[n+m]; 
for(; i< n && j<n;) { 
    if(a[i] < b[j]) { 
     array[k] = a[i]; 
     ++i; 
    } 
    else { 
     array[k] = b[j]; 
     ++j; 
    } 
    ++k; 
} 

while(i<n) { 
    array[k] = a[i]; 
    ++i; 
    ++k; 
} 
while(j<m) { 

    array[k] = b[j]; 
    ++j; 
    ++k; 
} 
for (int i = 0; i < n+m; ++i) { 
    cout<<array[i]; 
} 
cout<<endl; 

나는 그것을 뒤집어서 가장 큰 문자를 선택하여 뒤에서 추가하기를 원했습니다. 제한된 테스트를 통해 나는 이것을 잘 수행했다.

int n = a.size(), m = b.size(); 
int i =n-1, j=m-1, k=n+m-1; char array[n+m]; 
for(; i>=0 && j>=0;) { 
    if(a[i] > b[j]) { 
     array[k] = a[i]; 
     --i; 
    } 
    else { 
     array[k] = b[j]; 
     --j; 
    } 
    --k; 
} 
while(i>=0) { 
    array[k] = a[i]; 
    --i; 
    --k; 
} 
while(j>=0) { 
    array[k] = b[j]; 
    --j; 
    --k; 
} 
for (int i = 0; i < n + m; ++i) { 
    cout<<array[i]; 
} 
cout<<endl; 

그러나 이것이 항상 최적의 솔루션을 항상 제공하는지 확신 할 수 없습니다.

처음에는이 해결책이 맞습니까? 그렇다면 누군가가 항상 최적의 솔루션을 만드는 이유에 대해 약간의 증거를 줄 수 있습니다.

+1

나는 당신의 욕심이 알고리즘은 거의 정확 느낌이 있고 두 문자열에서 동일한 문자를 볼 때 당신이 당신의 검색 포크 경우는 작업을 시작해야한다. – Manvel

답변

1

욕심쟁이가 문제를 해결합니다. 이 문제를 해결하려면 두 문자열을 모두 방문해야합니다.

코드에서 첫 번째 루프에 대한 첫 번째 루프가 누락되었습니다. if(a[i] < b[j])if(a[i] <= b[j])이어야합니다. 코드 확인 here

+0

문자열 "cccc"및 "ccccaaaa"에 대해 출력이 "ccccaaaacccc"이어야하지만 프로그램에서 "ccccccccaaaa" – sudoer

+0

에 입력 순서를 반대로 지정하면됩니다. 당신은 누가 사전 적으로 작고 길이가 더 작은 지에 따라 a와 b 사이를 바꿀 수 있습니다. –

+0

a 및 b 입력 문자열을 전환하면 코드가 최적의 솔루션을 제공하지 못합니다. 나는이 변화가 모든 시나리오를 다룰 것이라고 생각하지 않는다. 내가 틀렸다면 나를 바로 잡아주세요. – thebenman

1

여기 내 의견을 기반으로 한 전체 솔루션입니다.

import string 
import random 

global brute_force_lowest 
global almost_greedy_lowest 

global brute_force_calls 
global almost_greedy_calls 

def brute_force(p, a, b): 
    global brute_force_lowest 
    global brute_force_calls 

    brute_force_calls += 1 

    if len(a) > 0: brute_force(p + a[0], a[1:], b) 
    if len(b) > 0: brute_force(p + b[0], a, b[1:]) 

    if len(a) == 0 and len(b) == 0: 
    if p < brute_force_lowest: brute_force_lowest = p 


def almost_greedy(p, a, b): 
    global almost_greedy_lowest 
    global almost_greedy_calls 

    almost_greedy_calls += 1 

    if len(a) == 0 and len(b) == 0: 
    if p < almost_greedy_lowest: almost_greedy_lowest = p 
    elif len(b) == 0: 
    almost_greedy(p + a, '', '') 
    elif len(a) == 0: 
    almost_greedy(p + b, '', '') 
    elif a[0] < b[0]: 
    almost_greedy(p + a[0], a[1:], b) 
    elif a[0] > b[0]: 
    almost_greedy(p + b[0], a, b[1:]) 
    else: 
    almost_greedy(p + a[0], a[1:], b) 
    almost_greedy(p + b[0], a, b[1:]) 


for j in range(10000): 
    a = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(2, 10))) 
    b = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(2, 10))) 
    brute_force_lowest = a + b 
    brute_force_calls = 0 
    brute_force('', a, b) 
    almost_greedy_calls = 0 
    almost_greedy_lowest = a + b 
    almost_greedy('', a, b) 
    print('%s, %s -> %s vs. %s (%.3f)' % (a, b, brute_force_lowest, almost_greedy_lowest, float(almost_greedy_calls)/brute_force_calls)) 
    if almost_greedy_lowest != brute_force_lowest: print 'ERROR' 

enter image description here 한 가지 흥미로운 통계는 우리가 'AB'에 알파벳을 제한 할 경우이 알고리즘은 평균 무력 알고리즘 후 약 10 배 빠른 속도로 작동합니다.

UPDATE 일부 최적화 :

def prefix_length(a): 
    for i in range(len(a)): 
    if a[i] != a[0]: return i 
    return len(a) 

def almost_greedy(p, a, b): 
    global almost_greedy_lowest 
    global almost_greedy_calls 

    almost_greedy_calls += 1 

    if p > almost_greedy_lowest: return 

    if len(a) == 0 and len(b) == 0: 
    if p < almost_greedy_lowest: almost_greedy_lowest = p 
    elif len(b) == 0: 
    almost_greedy(p + a, '', '') 
    elif len(a) == 0: 
    almost_greedy(p + b, '', '') 
    elif a[0] < b[0]: 
    almost_greedy(p + a[0], a[1:], b) 
    elif a[0] > b[0]: 
    almost_greedy(p + b[0], a, b[1:]) 
    else: 
    la = prefix_length(a) 
    almost_greedy(p + a[0] * la, a[la:], b) 
    lb = prefix_length(b) 
    almost_greedy(p + b[0] * lb, a, b[lb:]) 
+0

답변 해 주셔서 감사합니다. 파이썬 코드는 이해하기가 꽤 어렵습니다. 나는 곧 코드 주위에 머리를 감싼다. – thebenman

관련 문제