【问题标题】:Building bridges problem - how to apply longest increasing subsequence?搭建桥梁问题 - 如何应用最长递增子序列?
【发布时间】:2011-11-09 10:56:31
【问题描述】:

建桥问题如下:

有一条河流水平流经一个区域。河流上方和下方有一组城市。河流上方的每个城市都与河流下方的城市相匹配,并且您将获得此匹配作为一组配对。

您有兴趣在河上建造一组桥梁以连接最多的匹配城市对,但您必须以没有两座桥梁相互交叉的方式这样做。

设计一个算法来尽可能有效地解决这个问题。

听说这个问题和longest increasing subsequence问题有关,但是这里没看到怎么用。例如,如果我们得到了对

2  5  8  10
6  4  1  2

那么我们为 LIS 考虑哪个序列?

谢谢!

【问题讨论】:

  • 我认为问题并不像您可能怀疑的那样普遍……您能更详细地描述一下吗?
  • 考虑一张二维地图,其中有一条水平河流穿过其中心。南岸有 n 个城市,x 坐标为 a(1) ... a(n),北岸有 n 个城市,x 坐标为 b(1) ... b(n)。您希望通过桥梁连接尽可能多的南北城市对,以使没有两座桥梁交叉。连接城市时,只能连接北岸i市和南岸i市
  • @pranay- 银行中的城市是否按 x 坐标排序?还是按随机顺序排列?
  • @templatetypedef:它们可能是随机顺序的,也可能是排序的
  • 这不是说2 5 8 10是两者之间最长的吗?

标签: algorithm dynamic-programming


【解决方案1】:

首先考虑对:(2,6), (5, 4), (8, 1), (10, 2),根据对的第一个元素对其进行排序(在这种情况下已经排序)并计算对的第二个元素的列表,从而计算6 4 1 2上的 LIS ,即1 2。因此,您要查找的非重叠行是 (8, 1)(10, 2)

【讨论】:

  • 不客气 ;)..如果你还没有这样做,请给我 +1 ;D
  • 不错的解决方案。我也+1。 :)
  • 是的,我也是!比接受的更好!短而甜
【解决方案2】:

要了解如何使用最长递增子序列算法来解决此问题,让我们先从一些直觉开始,然后再构建解决方案。由于您只能在匹配索引的城市之间建造桥梁,因此您可以将最终建造的一组桥梁视为您能找到的最大的一组不包含任何交叉点的桥梁。那么什么情况下会过境呢?

让我们看看什么时候会发生这种情况。假设我们对他们的第一个城市建造的所有桥梁进行排序。如果两座桥交叉,那么我们必须有一些桥 (ai, bi) 使得对于另一个桥 (aj, bj) 以下之一成立:

第一种情况是说有一座桥的顶部城市比我们桥的起点更靠右,而它的底部城市比我们桥的终点更靠左,第二种情况处理相反的情况.

鉴于该属性需要保持,我们需要确保对于每组桥,我们有以下两个属性中的一个恰好适用于任何一对桥(ai,b i), (aj, bj): 任一

  • ai ≤ aj 和 bi ≤ bj

  • ai ≥ aj 和 bi ≥ bj

换句话说,如果我们要按照它们的第一个坐标对桥进行排序,那么第二个坐标的集合总是会增加。同样,如果我们按照桥的第二个坐标对桥进行排序,第一个坐标总是递增的。

我们刚刚定义的属性在桥集上定义了一个偏序≤both,我们说 (ai, bi ) ≤both (aj, bj) 如果 ai ≤ a j 和 bi ≤ bj。请注意,这不是全序 - 例如,(1, 2) 与 (2, 1) 无法比较 - 但它是偏序,因为它具有自反性、反对称性和传递性。

鉴于此,问题的目标是找到我们可以通过这种关系完全排序的最大元素集合,因为如果我们有一个包含两个无法比较的元素的集合,那么这些元素必然代表过桥。换句话说,我们想要找到偏序中最长的链。一种方法是在 O(n2) 时间内将每个元素与其他元素进行比较,看看哪些元素可以按 ≤both 排序。这将产生一个有向无环图,其中对 (ai, bi) 具有到 (aj, b j) iff (ai, bi) ≤both (aj, bj)。一旦我们有了这个有向无环图,我们就可以找到longest path in the graph 来找到被≤both 称为可比较的最大元素集,然后给出问题的解决方案。因此,整体运行时间为 O(n2)。

但是,我们可以做得比这更好。上述算法的问题在于,我们无法轻易判断元素之间的比较,因此我们必须明确地将每个城市与其他城市进行比较。

2  5  8 10
6  4  1  2 

让我们按底行对城市进行排序:

8 10  5  2
1  2  4  6

现在,这是一个非常酷的观察。如果我们有元素按它们的底行排序,那么我们可以通过查看它们在顶行中的位置来判断两对是否可以按 ≤both 排序。如果第一对在第二对的左边,我们立即知道第一对的第二个元素小于第二对的第二个元素,因为我们已经按照第二个坐标对它们进行了排序。然后,如果第一对的第一个元素小于第二对的第一个元素,我们就可以将这对元素构建在一起。因此,如果我们想找到一组可以一起建造的桥,我们正在寻找顶行的递增子序列,因为在这种情况下,当我们从从左到右。找到最长的递增子序列就可以解决这个问题。由于我们可以通过 O(n log n) 中的第二个字段对对进行排序,并在 O(n log n) 中找到最长的递增子序列,因此这是该问题的 O(n log n) 解决方案!

哇!希望这个答案能详细说明问题!

【讨论】:

  • 对 dag 的伟大直觉
  • 你写这个答案已经 3 年多了.. 但仍然很有帮助.. :D
  • @mohit 你能详细说明一下吗?你会使用哪两个序列?
【解决方案3】:

这是一个动态规划问题,甚至可以建模为最长子序列问题。考虑河流以北的城市坐标为 a1,a2,a3..aN。现在在河流的南部找到相应的城市,并将它们标记为 a1,a2,a3..aN。 那么问题的解决方案将是由河流南北的 aI 形成的字符串的最长公共子序列。

【讨论】:

    【解决方案4】:

    这是解决上述问题的 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;
    }
    

    【讨论】:

    • 但没有解释或 cmets 解释它为什么起作用。
    【解决方案5】:

    这是该问题的 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_;
                }
            }
    
        }
    

    【讨论】:

      【解决方案6】:

      排序一个列表,找到其他.C++代码中的LIS->

      #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;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-10-28
        • 1970-01-01
        • 2012-09-09
        • 2013-07-03
        • 2017-01-07
        • 1970-01-01
        相关资源
        最近更新 更多