web-dev-qa-db-ja.com

橋を架ける問題-長くなるサブシーケンスを適用する方法?

ブリッジの問題は次のように述べられています。

ある地域を水平に流れる川があります。川の上下に一連の都市があります。川の上の各都市は川の下の都市と一致し、この一致はペアのセットとして与えられます。

一致する都市の最大数のペアを接続するために川を渡る橋のセットを構築することに興味がありますが、2つの橋が互いに交差しないようにする必要があります。

この問題をできるだけ効率的に解決するアルゴリズムを考案してください。

この問題は 最も長い増加するサブシーケンス 問題に関連していると聞いたことがありますが、ここではそれを使用する方法がわかりません。たとえば、ペアが与えられた場合

2  5  8  10
6  4  1  2

次に、LISについてどのシーケンスを検討しますか?

ありがとう!

28
pranay

この問題を解決するために、最も長く増加しているサブシーケンスアルゴリズムをどのように使用するかを構築するために、いくつかの直感から始めて、ソリューションを構築します。一致するインデックスでのみ都市間に橋を構築できるため、最終的に構築する一連の橋は、交差点を含まない、見つけることができる最大のペアのセットと考えることができます。それでは、どのような状況で横断歩道がありますか?

これがいつ起こるか見てみましょう。最初の都市によって建設されたすべての橋を分類するとします。 2つの橋が交差する場合、いくつかの橋(a、b)他のブリッジ(aj、bj)次のいずれかが成り立つ:

  • a <aj そしてb > bj
  • a > aj そしてb <bj

この最初のケースは、上部の都市が橋の始点よりも右にあり、下部の都市が橋の終わりよりも左にある橋があり、2番目のケースは反対のケースを処理することを示しています。

このプロパティが保持する必要があることを考えると、ブリッジのすべてのセットについて、次の2つのプロパティのいずれかがブリッジのペア(a、b)、(aj、bj):どちらか

  • a ≤aj そしてb ≤bj

または

  • a ≥aj そしてb ≥bj

つまり、橋を最初の座標で並べ替えると、2番目の座標のセットは常に増加します。同様に、橋を2番目の座標で並べ替えると、最初の座標は常に増加します。

今定義したプロパティは、部分的な順序≤を定義します両方とも 私たちはそれを言う橋のセットで(a、b)≤両方とも (aj、bj) もし ≤aj そしてb ≤bj。これは完全な順序ではないことに注意してください。たとえば、(1、2)は(2、1)と比較できませんが、再帰的、反対称的、推移的であるため、部分的な順序です。

この場合、問題の目的は、この関係によって完全に順序付けできる最大の要素のセットを見つけることです。これは、2つの比較できない要素を含むセットがある場合、これらの要素は交差する橋を表す必要があるためです。つまり、部分的な順序で最も長いチェーンを見つけたいと考えています。これを行う1つの方法は、O(n2)時間、各要素を他の要素と比較し、どの要素を≤で順序付けできるかを確認します両方とも。これにより、ペア(a、b)は(aj、bj)iff(a、b)≤両方とも (aj、bj)。この有向非循環グラフを作成したら、次に グラフ内の最長パス を見つけて、≤で比較可能な要素の最大セットを見つけることができます。両方とも、問題の解決策を提供します。したがって、全体的なランタイムはO(n2)。

ただし、これよりも大幅に改善できます。上記のアルゴリズムの問​​題は、要素が互いにどのように比較されるかを簡単に判断できないため、各都市を他の都市と明示的に比較する必要があることです。

2  5  8 10
6  4  1  2 

下の行で都市を並べ替えましょう。

8 10  5  2
1  2  4  6

さて、これが本当にクールな観察です。要素を下の行でソートした場合、2つのペアが≤で順序付け可能かどうかを確認できます両方とも 上の行の位置を確認してください。最初のペアが2番目のペアの左側にある場合、2番目の座標でソートしたため、最初のペアの2番目の要素は2番目のペアの2番目の要素よりも小さいことがすぐにわかります。次に、最初のペアの最初のエレメントが2番目のペアの最初のエレメントよりも小さい場合に、エレメントのペアを一緒に構築できるようにします。したがって、一緒に構築できるブリッジのセットを見つけたい場合は、上の行のサブシーケンスの増加を探します。その場合、ペアの最初と2番目の要素の両方が、左から右へ。次に、最も長く増加するサブシーケンスを見つけると、この問題が解決します。 O(n log n)の2番目のフィールドでペアを並べ替え、O(n log n)で最も長く増加するサブシーケンスを見つけることができるため、これは問題のO(n log n)ソリューションです!

ふew!この答えが詳細を説明していることを願っています!

52
templatetypedef

ここにJava問題の実装があります。

    package DP;

    import Java.util.Arrays;
    import Java.util.Comparator;

    public class BuildingBridges {

        public static void main(String[] args) {
            Pair[] A = new Pair[7];
            A[0] = new Pair(22,4);
            A[1] = new Pair(2,6);
            A[2] = new Pair(10,3);
            A[3] = new Pair(15,12);
            A[4] = new Pair(9,8);
            A[5] = new Pair(17,17);
            A[6] = new Pair(4,2);

            System.out.println(lis(A));
        }

        public static int lis(Pair[] A){
            Arrays.sort(A, new Comparator<Pair>() {
                @Override
                public int compare(Pair o1, Pair o2) {
                    return o1.x - o2.x;
                }
            });

            int n = A.length;
            int max = 0;
            int[] dp = new int[n];
            Arrays.fill(dp, 1);

            for(int i=1; i<n; i++){
                for(int j=0; j<i; j++){
                    if(A[i].y > A[j].y){
                        dp[i] = Math.max(dp[i], dp[j]+1);
                    }
                }
                max = Math.max(max, dp[i]);
            }

            return max;
        }

        public static class Pair{
            int x, y;
            public Pair(int x_, int y_){
                x = x_;
                y = y_;
            }
        }

    }
5
Bin Feng

これは動的プログラミング問題であり、最長サブシーケンス問題としてもモデル化できます。川の北にある都市の座標をa1、a2、a3..aNと見なします。次に、川の南にある対応する都市を見つけて、a1、a2、a3..aNとしてマークします。この問題の解決策は、川の北と南にあるaIによって形成されるストリングの最も長い共通部分列になります。

4
raZ0r

1つのリストを並べ替え、他のリストでLISを見つけます。C++コード->

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(pair<int,int> a, pair<int,int> b){
    return a.first<b.first;
}

int bridges(vector<pair<int,int> > connect){
    int i, j, n=connect.size();
    sort(connect.begin(),connect.end(),cmp);
    vector<int> lis(n,1);
    int m=0;
    for(i=0;i<n;i++){
        for(j=i-1;j>=0;j--){
            if(connect[i].second>connect[i].first)lis[i]=max(lis[i],lis[j]+1);
        }
        m=max(m,lis[i]);
    }
    return m;
}

int main(){
    int n, i;
    cin >> n;
    vector<pair<int,int> > a(n);
    for(i=0;i<n;i++)cin >> a[i].first >> a[i].second;
    cout << bridges(a) <<endl;
    return 0;
}
1
Arun Siddharth

これは、上記の問題のC++で動作するコードです。

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

struct pairs{
int x;
int y;  
};

bool myf(struct pairs p1,struct pairs p2){
return p1.x<p2.x;   
}

int lis(struct pairs a[],int n){
sort(a,a+n,myf);

int lis[n];

for(int i=0;i<n;i++)
    lis[i]=1;

for(int i=1;i<n;i++){

    for(int j=0;j<i;j++){
        if((a[j].y<a[i].y)&&(lis[i]<lis[j]+1))
            lis[i]=lis[j]+1;
    }
}

int max=lis[0];

for(int i=1;i<n;i++){
    if(max<lis[i])
        max=lis[i]; 
}

return max;
}

int main()
{
struct pairs arr[100];
int n;
cin>>n;
for(int i=0;i<n;i++){
    cin>>arr[i].x>>arr[i].y;    
}

int max=lis(arr,n);
cout<<max<<"\n";

return 0;
}
0
dark_shadow