2016-06-15 2 views
0

かなり単純なサブ問題に遭遇したときに問題を解決していました。 2つの文字列S1S2が与えられた場合、merge(S1,S2)は、2つの文字列S1S2を散在させることによって得られた文字列を表し、両方の文字の順序を維持して結果の文字列が辞書編集的に最小です。今2つの文字列をマージして、辞書的に最も小さなマージされた文字列を生成します。

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

私はあなたの貪欲アルゴリズムは、ほぼ正しい感覚を持っていて、両方の文字列で同じ文字を見たとき、あなたの検索をfork場合には、作業を開始する必要があります。 – Manvel

答えて

1

貪欲が問題を解決します。この問題を解決するには、両方の文字列を必ず確認する必要があります。

あなたのコードでは、最初のforループif(a[i] < b[j])のコードは、if(a[i] <= b[j])でなければなりません。 コードを確認してくださいhere

+0

文字列 "cccc"& "ccccaaaa"の出力は "ccccaaaacccc"にする必要がありますが、プログラムでは "ccccccccaaaa" – sudoer

+0

に入力の順序を逆順にするだけです。あなたはlexicographical小規模で長さが小さい人に応じて、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

あなたの答えをありがとう。 Pythonコードは私が理解するのがかなり難しいです。私はすぐにコードの周りに私の頭を包むように答えとしてこれを受け入れます。 – thebenman

関連する問題