【问题标题】:Maximum sum of non consecutive elements非连续元素的最大总和
【发布时间】:2011-05-28 02:39:02
【问题描述】:

给定一个正整数数组,从这个数组中找出不连续元素的最有效算法是什么,当它们加在一起时,会产生最大和?

【问题讨论】:

  • 只是想澄清一下。我认为 {1,2,3,8,9} 的总和是 1+3+9 ...
  • 如果仔细阅读,我认为问题的陈述是明确的。 @belaisarius,{1, 3, 9} 将是 {1, 2, 3, 8, 9} 的正确答案。但不要由此假设仅选择替代元素就可以工作。
  • @Frederick 是的,也许是个坏例子。我只是想表明不连续的部分在答案和 cmets 中丢失了

标签: arrays algorithm


【解决方案1】:

动态编程?给定一个数组A[0..n],让M(i) 成为使用索引为0..i 的元素的最优解。然后是M(-1) = 0(在循环中使用)、M(0) = A[0]M(i) = max(M(i - 1), M(i - 2) + A[i]) for i = 1, ..., nM(n) 是我们想要的解决方案。这是 O(n)。您可以使用另一个数组来存储为每个子问题做出的选择,从而恢复实际选择的元素。

【讨论】:

  • 我还想存储产生最大和的元素的索引,我该怎么做?
【解决方案2】:

A 为给定数组,Sum 为另一个数组,这样Sum[i] 表示来自arr[0]..arr[i] 的非连续元素的最大总和。

我们有:

Sum[0] = arr[0]
Sum[1] = max(Sum[0],arr[1])
Sum[2] = max(Sum[0]+arr[2],Sum[1])
...
Sum[i] = max(Sum[i-2]+arr[i],Sum[i-1]) when i>=2

如果sizearr 中的元素数,那么sum[size-1] 就是答案。

可以按自上而下的顺序编写一个简单的递归方法:

int sum(int *arr,int i) {
        if(i==0) {
                return arr[0];
        }else if(i==1) {
                return max(arr[0],arr[1]);
        }
        return max(sum(arr,i-2)+arr[i],sum(arr,i-1));
}

上面的代码效率很低,因为它进行了详尽的重复递归调用。为了避免这种情况,我们通过使用名为sum 的辅助数组来使用记忆化:

int sum(int *arr,int size) {
        int *sum = malloc(sizeof(int) * size);
        int i;

        for(i=0;i<size;i++) {
                if(i==0) {
                        sum[0] = arr[0];
                }else if(i==1) {
                        sum[1] = max(sum[0],arr[1]);
                }else{
                        sum[i] = max(sum[i-2]+arr[i],sum[i-1]);
                }
        }    
        return sum[size-1];
}

在空间和时间上都是O(N)

【讨论】:

  • O(N) 额外的空间可以避免,相反我们只需要使用 2 个 xtra 变量来跟踪每次迭代结束时的 sum[i - 1] 和 sum[i - 2]。
  • 当我的测试用例说它应该是10时,这个解决方案给我6 for 1 2 3 4
  • @0x499602D2 6 是正确答案,10所有 元素的总和,所以在非约束下不可能是正确答案连续性。
  • @RobinNabel 对,我没注意到 non 连续。
【解决方案3】:

时间 O(N) 和空间 O(1) (DP) 解:

int dp[2] = {a[0], a[1]};
for(int i = 2; i < a.size(); i++)
{
    int temp = dp[1];
    dp[1] = dp[0] + a[i];
    dp[0] = max(dp[0], temp);
}    
int answer = max(dp[0], dp[1]);

【讨论】:

  • 如果您可以添加一些关于每行功能的 cmets,那就太好了。这是一个非常理想且干净的解决方案,但对于某些人来说,它有点过于优雅,如果没有额外的注释就无法理解。
  • 如何找到索引?
  • 当我的测试用例说它应该是10时,这个解决方案给了我6 for 1 2 3 4
  • 问题不清楚。上述解决方案是找到没有两个元素连续的最大子数组。上述解决方案不适用于具有连续和非连续元素的子数组情况。
  • @0x499602D2 这将是在连续元素的情况下。给定的解决方案是针对非连续元素求和。
【解决方案4】:
/**
 * Given an array of positive numbers, find the maximum sum of elements such
 * that no two adjacent elements are picked
 * Top down dynamic programming approach without memorisation.
 * An alternate to the bottom up approach.
 */

public class MaxSumNonConsec {

public static int maxSum(int a[], int start, int end) {
    int maxSum = 0;

    // Trivial cases
    if (start == end) {
        return a[start];
    } else if (start > end) {
        return 0;
    } else if (end - start == 1) {
        return a[start] > a[end] ? a[start] : a[end];
    } else if (start < 0) {
        return 0;
    } else if (end >= a.length) {
        return 0;
    }

    // Subproblem solutions, DP
    for (int i = start; i <= end; i++) {
        int possibleMaxSub1 = maxSum(a, i + 2, end);
        int possibleMaxSub2 = maxSum(a, start, i - 2);

        int possibleMax = possibleMaxSub1 + possibleMaxSub2 + a[i];
        if (possibleMax > maxSum) {
            maxSum = possibleMax;
        }
    }

    return maxSum;
}

public static void main(String args[]) {
    int a[] = { 8, 6, 11, 10, 11, 10 };
    System.out.println(maxSum(a, 0, a.length - 1));
}
}

【讨论】:

  • 补充一下,上面是一个简单的递归实现,没有记忆。它的运行时间可以通过缓存/记忆重复子问题的解决方案来改进,例如通过将计算的子问题添加到哈希表,然后在计算新的子问题之前检查哈希表。
【解决方案5】:

@Ismail Badawi 的解决方案在以下情况下似乎不起作用:让我们采用数组:8, 3, 1, 7 然后在这种情况下,算法返回 max sum = 9 而它应该是 15

给定一个数组A[0..n] 来纠正它,让M(i) 成为使用索引为0..i 的元素的最佳解决方案。然后M(0) = A[0]M(i) = max(M(i - 1), M(i - 2) + A[i], M(i-3) + A[i]) for i = 3, ..., nM(n) 是我们想要的解决方案。这是 O(n)。

【讨论】:

  • Ismail 的算法为您的测试用例提供了正确答案。 m[0]=m[1]=8, m[2]= 9, m[3]= max(m[2],m[1] + 7) = 15
【解决方案6】:

IIUC:假设您的数组是 1,2,3,4,5 那么 3+5 将是“正确的”而 4+5 不是,这意味着您必须找到最大的数字并检查它们是否连续.因此,一种算法是使用第二个数组,通过遍历原始数组并找到最大的非连续整数来填充您需要添加的元素数量,然后将其相加。

对于上面的数组我猜是 [1,3], [1,4], [1,5], [1,3,5], [2,4], [2,5], [3, 5] 将是要求和的有效非连续整数,在这种情况下,最大和为 9 [1,3,5]。因此,为了适应上述算法,我建议您使用几个临时数组逐步遍历数组,以找到所有不连续的整数列表,然后检查哪个是最大的。请记住,“大多数元素”并不意味着“最大和”。

【讨论】:

  • @Jason Williams:是的,我想我现在“解决”了问题;)
  • 找到所有不连续元素的集合,然后找到每个集合的总和,然后选择总和最大的集合是正确的算法。但它会是最有效的吗?我怀疑我们可以找到更好的东西(也许是线性时间),但我不确定那个算法可能是什么。
【解决方案7】:

动态编程解决方案是最优雅的。 它适用于不应考虑的两个数字之间的任何距离值。 但是对于连续数字约束的 k=1,我尝试使用回溯。

要比较最大和的不同模式。以下是列表:

Number of patterns for 1 = 1    
[1]
Number of patterns for 2 = 2    
[1][2]
Number of patterns for 3 = 2
[1, 3][2]
Number of patterns for 4 = 3
[1, 3][1, 4][2, 4]
Number of patterns for 5 = 4
[1, 3, 5][1, 4][2, 4][2, 5]
Number of patterns for 6 = 5
[1, 3, 5][1, 3, 6][1, 4, 6][2, 4, 6][2, 5]
Number of patterns for 7 = 7
[1, 3, 5, 7][1, 3, 6][1, 4, 6][1, 4, 7][2, 4, 6][2, 4, 7][2, 5, 7]
Number of patterns for 8 = 9
[1, 3, 5, 7][1, 3, 5, 8][1, 3, 6, 8][1, 4, 6, 8][1, 4, 7][2, 4, 6, 8][2, 4, 7][2, 5, 7][2, 5, 8]
Number of patterns for 9 = 12
[1, 3, 5, 7, 9][1, 3, 5, 8][1, 3, 6, 8][1, 3, 6, 9][1, 4, 6, 8][1, 4, 6, 9][1, 4, 7, 9][2, 4, 6, 8][2, 4, 6, 9][2, 4, 7, 9][2, 5, 7, 9][2, 5, 8] 

以下是java中的代码:

public class MaxSeqRecursive {

    private static int num = 5;
    private static int[] inputArry = new int[] { 1,3,9,20,7 };
    private static Object[] outArry;
    private static int maxSum = 0;

    public static void main(String[] args) {

        List<Integer> output = new ArrayList<Integer>();
        output.add(1);
        convert(output, -1);
        for (int i = 0; i < outArry.length; i++) {
            System.out.print(outArry[i] + ":");
        }

        System.out.print(maxSum);
    }

    public static void convert( List<Integer> posArry, int prevValue) {

        int currentValue = -1;

        if (posArry.size() == 0) {
            if (prevValue == 2) {
                return;
            } else {
                posArry.add(2);
                prevValue = -1;
            }

        }

        currentValue = (int) posArry.get(posArry.size() - 1);

        if (currentValue == num || currentValue == num - 1) {
            updateMax(posArry);
            prevValue = (int) posArry.get(posArry.size() - 1);
            posArry.remove(posArry.size() - 1);
        } else {
            int returnIndx = getNext(posArry, prevValue);
            if (returnIndx == -2)
                return;

            if (returnIndx == -1) {
                prevValue = (int) posArry.get(posArry.size() - 1);
                posArry.remove(posArry.size() - 1);
            } else {
                posArry.add(returnIndx);
                prevValue = -1;
            }
        }
        convert(posArry, prevValue);
    }

    public static int getNext( List<Integer> posArry, int prevValue) {
        int currIndx = posArry.size();
        int returnVal = -1;
        int value = (int) posArry.get(currIndx - 1);

        if (prevValue < num) {
            if (prevValue == -1)
                returnVal = value + 2;
            else if (prevValue - value < 3)
                returnVal = prevValue + 1;
            else
                returnVal = -1;
        }

        if (returnVal > num)
            returnVal = -1;

        return returnVal;
    }

    public static void updateMax(List posArry) {
        int sum = 0;
        for (int i = 0; i < posArry.size(); i++) {
            sum = sum + inputArry[(Integer) posArry.get(i) - 1];
        }
        if (sum > maxSum) {
            maxSum = sum;
            outArry = posArry.toArray();
        }
    }
}

Time complexity: O( number of patterns to be compared) 

【讨论】:

  • 看起来这个算法不是多项式而是指数的。模式随着元素的数量呈指数增长(0,1,2,2,3,4,5,7,9,12,16,21,28,37,49,65,86,114,151,200,265,351,465,616)。 :-(
  • 有趣的是,这种模式类似于斐波那契数列,但有细微的变化 ::: F(n) = F(n-2) + F(n-3) !!!!
【解决方案8】:

另一个 Java 实现(以线性时间运行)

public class MaxSum {

private static int ofNonConsecutiveElements (int... elements) {
    int maxsofar,maxi2,maxi1;

    maxi1 = maxsofar = elements[0];
    maxi2 = 0;

    for (int i = 1; i < elements.length; i++) {
        maxsofar =  Math.max(maxi2 + elements[i], maxi1);
        maxi2 =  maxi1;
        maxi1 = maxsofar;
    }
    return maxsofar;        
}

public static void main(String[] args) {
    System.out.println(ofNonConsecutiveElements(6, 4, 2, 8, 1));
}
}

【讨论】:

  • { 1,2,13,4,5,9};试试这个输入,它会返回 23 而不是 22
【解决方案9】:

我的解决方案是 O(N) 时间和 O(1) 空间。

private int largestSumNonConsecutive(int[] a) {
    return largestSumNonConsecutive(a, a.length-1)[1];
}
private int[] largestSumNonConsecutive(int[] a, int end) {  //returns array largest(end-1),largest(end)
    if (end==0) return new int[]{0,a[0]};

    int[] largest = largestSumNonConsecutive(a, end-1);
    int tmp = largest[1];
    largest[1] = Math.max(largest[0] + a[end], largest[1]);
    largest[0] = tmp;

    return largest;
}

【讨论】:

  • 这实际上是 O(n) 空间,因为对 largestSumNonConsecutive() 的递归调用会占用堆栈空间。
【解决方案10】:
int nonContigousSum(vector<int> a, int n) {
    if (n < 0) {
        return 0;
    }
    return std::max(nonContigousSum(a, n - 1), nonContigousSum(a, n - 2) + a[n]);
}

这是我们可以解决这个问题的递归方法 (动态编程的最佳子结构标志。 这里我们考虑两种情况,首先我们排除 a[n],然后我们包括 a[n] 并返回找到的那些子案例的最大值。 我们基本上是找到数组的所有子集,并返回具有最大总和的非连续数组的长度。 使用tabulation or memoization 来避免相同的子问题。

【讨论】:

  • 不鼓励仅使用代码的答案。然后:请研究help center 以了解如何正确格式化您的输入。为 C++ 代码设置“运行代码 sn-p”根本没有意义,是吗?!
  • 不是 (n-2) 而不是 (n-1)?您是否假设数组从索引 1 开始?
  • @TechJunkie,谢谢,我没有阅读非连续元素部分。
【解决方案11】:

给我一​​分钱。

public class Problem {

  /**
   * Solving by recursion, top down approach. Always try this recursion approach and then go with
   * iteration. We have to add dp table to optimize the time complexity.
   */
  public static int maxSumRecur(int arr[], int i) {
    if(i < 0) return 0;
    if(i == 0) return arr[0];
    if(i == 1) return Math.max(arr[0], arr[1]);

    int includeIthElement = arr[i] + maxSumRecur(arr, i-2);
    int excludeIthElement = maxSumRecur(arr, i-1);
    return Math.max(includeIthElement, excludeIthElement);
  }

  /**
   * Solving by iteration. Bottom up approach.
   */
  public static void maxSumIter(int arr[]) {
    System.out.println(Arrays.toString(arr));
    int dp[] = new int[arr.length];
    dp[0] = arr[0];
    dp[1] = Math.max(arr[0], arr[1]);

    for(int i=2; i <= arr.length - 1; i++) {
      dp[i] = Math.max(arr[i] + dp[i-2], dp[i-1]);
    }

    System.out.println("Max subsequence sum by Iteration " + dp[arr.length - 1] + "\n");
  }

  public static void maxSumRecurUtil(int arr[]) {
    System.out.println(Arrays.toString(arr));
    System.out.println("Max subsequence sum by Recursion " + maxSumRecur(arr, arr.length - 1) +
        "\n");
  }

  public static void main(String[] args) {
    maxSumRecurUtil(new int[]{5, 5, 10, 100, 10, 5});
    maxSumRecurUtil(new int[]{20, 1, 2, 3});

    maxSumIter(new int[]{5, 5, 10, 100, 10, 5});
    maxSumIter(new int[]{20, 1, 2, 3});

  }

}

【讨论】:

    【解决方案12】:

    制作一个数字列表,该列表是迄今为止每个数字对应的奇数或偶数和;例如对于[1,2,4,1,2,3,5,3,1,2,3,4,5,2] 的输入,奇偶和将为[1,2,5,3,7,6,12,9,13,11,16,15,21,17]

    现在向后遍历列表,贪婪地求和,但跳过那些奇/偶和小于下一个要考虑的元素的元素。

    src = [1,2,4,1,2,3,5,3,1,2,3,4,5,2]
    
    odd_even_sums = src[:2]
    for i in xrange(2,len(src)):
        odd_even_sums.append(src[i] + odd_even_sums[i-2])
    
    best = []
    for i in xrange(len(src)-1,-1,-1):
        if i == 0:
            best.append(i)
        elif odd_even_sums[i-1] > odd_even_sums[i]:
            pass
        elif odd_even_sums[i-1] == odd_even_sums[i]:
            raise Exception("an exercise for the reader")
        else:
            best.append(i)
    
    best.reverse()
    
    print "Best:",",".join("%s=%s"%(b,src[b]) for b in best)
    print "Scores:",sum(odd_even_sums[b] for b in best)
    

    输出:

    Best: 0=1,1=2,2=4,4=2,6=5,8=1,10=3,12=5
    Scores: 77
    

    【讨论】:

      【解决方案13】:
      public static int findMaxSum(int[] a){
              int sum0=0; //will hold the sum till i-2        
              int sum1=0;//will hold the sum till i-1
              for(int k : a){
                  int x=Math.max(sum0+k, sum1);//max(sum till (i-2)+a[i], sum till (i-1))
                  sum0=sum1;
                  sum1=x;
              }
              return sum1;
          }
      

      以下是算法的关键:

      max(max sum till (i-2)+a[i], max sum till (i-1))

      O(N) 时间复杂度和 O(1) 空间复杂度。

      【讨论】:

      • 在此,我们取数组的第 i 个元素加上 dp 数组的第 i-2 个元素与 dp 数组的第 i-1 个元素之和之间的最大值。但可能是第 i-1 个元素未用于在 dp[i-1] 处求和。如果是这种情况,我们也可以在技术上添加第 i 个元素,对吗?有人可以解释为什么这不是必需的吗?
      【解决方案14】:

      一个相当幼稚但完整的实现。 递归方程是 T(n) = n^2 + nT(n-3),如果我没记错的话,它会导致指数时间。 (n-3) 来自一个数字不能与自身/前一个/下一个数字相加的事实。

      程序报告构成总和的组成列表(这些列表中有多个呈指数增长的,但它只选择一个)。

      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      import java.util.Map.Entry;
      
      public class MaxSumNoAdjacent {
      
          private static class Sum {
              int sum;
              List<Integer> constituents = new ArrayList<>();
      
              Sum(int sum, List<Integer> constituents) {
                  this.sum = sum;
                  this.constituents = constituents;
              }
      
              @Override
              public String toString() {
                  return "sum: " + sum + " " + constituents.toString(); 
              }
          }
      
          public static Sum maxSum(int[] arr) {
              List<Integer> input = new ArrayList<>();
              for (int i : arr) {
                  if (i != Integer.MIN_VALUE) { //Integer.MIN_VALUE indicates unreachability
                      input.add(i);
                  }
              }
      
              if (input.size() == 0) {
                  return null;
              }
      
              if (input.size() == 1) {
                  List<Integer> constituents = new ArrayList<>();
                  constituents.add(input.get(0));
                  return new Sum(input.get(0), constituents);
              }
      
              if (input.size() == 2) {
                  int max = Math.max(input.get(0), input.get(1));
                  List<Integer> constituents = new ArrayList<>();
                  constituents.add(max);
                  return new Sum(max, constituents);
              }
      
              Map<Integer, int[]> numberAndItsReachability = new HashMap<>();
              for (int i = 0; i < input.size(); i++) {
                  int[] neighbours = new int[input.size()];
                  if (i > 0) {
                      neighbours[i-1] = Integer.MIN_VALUE; //unreachable to previous
                  }
      
                  if (i < input.size()-1) {
                      neighbours[i+1] = Integer.MIN_VALUE; //unreachable to next
                  }
      
                  neighbours[i] = Integer.MIN_VALUE; //unreachable to itself
      
                  for (int j = 0; j < neighbours.length; j++) {
                      if (neighbours[j] == 0) {
                          neighbours[j] = input.get(j); //remember values of reachable neighbours
                      }
                  }
      
                  numberAndItsReachability.put(input.get(i), neighbours);
              }
      
              Sum maxSum = new Sum(Integer.MIN_VALUE, null);
              for (Entry<Integer, int[]> pair : numberAndItsReachability.entrySet()) {
                  Sum sumMinusThisNumber = maxSum(pair.getValue()); //call recursively on its reachable neighbours
                  if (sumMinusThisNumber != null) {
                      int candidateSum = sumMinusThisNumber.sum + pair.getKey();
                      if (maxSum.sum < candidateSum) {
                          sumMinusThisNumber.constituents.add(pair.getKey());
                          maxSum = new Sum(candidateSum, sumMinusThisNumber.constituents);
                      }
                  }
      
              }
      
              return maxSum;
          }
      
          public static void main(String[] args) {
              int[] arr1 = {3,2,5,10,7};
              int[] arr2 = {3,2,7,10};
              int[] arr3 = {5,5,10,40,50,35};
              int[] arr4 = {4,4,4,4};
              System.out.println(maxSum(arr1).toString());
              System.out.println(maxSum(arr2).toString());
              System.out.println(maxSum(arr3).toString());
              System.out.println(maxSum(arr4).toString());
          }
      
      }
      

      【讨论】:

        【解决方案15】:

        这里有一个C#版本供参考(你可以参考:http://dream-e-r.blogspot.com/2014/07/maximum-sum-of-non-adjacent-subsequence.html):

        为了使用动态规划解决问题,应该有一个具有最优子结构和重叠子问题属性的解决方案。并且当前问题具有最优子结构性质。 比如说,f(i) 被定义为 'i' 项的非相邻元素的最大子序列和,那么

        f(i) = 0 如果 i = 0 最大值 (f(i-1), f(i-2) + a[i])

        以下是相同的算法(没有 它可以在没有“记录”中封装数据的情况下解决——我只是更喜欢这种方式)——这应该说明上述想法:

        int FindMaxNonAdjuscentSubsequentSum(int[] a)
                {
                    a.ThrowIfNull("a");
                    if(a.Length == 0)
                    {
                        return 0;
                    }
                    Record r = new Record()
                    {
                        max_including_item = a[0],
                        max_excluding_item = 0
                    };
                    for (int i = 1; i < a.Length; i++)
                    {
                        var t = new Record();
                        //there will be only two cases
                        //1. if it includes the current item, max is maximum of non adjuscent sub
                        //sequence sum so far, excluding the last item
                        t.max_including_item = r.max_excluding_item + a[i];
                        //2. if it excludes current item, max is maximum of non adjuscent subsequence sum
                        t.max_excluding_item = r.Max;
                        r = t;
                    }
                    return r.Max;
                }
        

        单元测试

        [TestMethod]
                [TestCategory(Constants.DynamicProgramming)]
                public void MaxNonAdjascentSubsequenceSum()
                {
                    int[] a = new int[] { 3, 2, 5, 10, 7};
                    Assert.IsTrue(15 == this.FindMaxNonAdjuscentSubsequentSum(a));
                    a = new int[] { 3, 2, 5, 10 };
                    Assert.IsTrue(13 == this.FindMaxNonAdjuscentSubsequentSum(a));
                    a = new int[] { 5, 10, 40, 50, 35 };
                    Assert.IsTrue(80 == this.FindMaxNonAdjuscentSubsequentSum(a));
                    a = new int[] { 1, -1, 6, -4, 2, 2 };
                    Assert.IsTrue(9 == this.FindMaxNonAdjuscentSubsequentSum(a));
                    a = new int[] { 1, 6, 10, 14, -5, -1, 2, -1, 3 };
                    Assert.IsTrue(25 == this.FindMaxNonAdjuscentSubsequentSum(a));
                }
        

        在哪里

        public static int Max(int a, int b)
                {
                    return (a > b) ? a : b;
                }
                class Record
                {
                    public int max_including_item = int.MinValue;
                    public int max_excluding_item = int.MinValue;
                    public int Max
                    {
                        get
                        {
                            return Max(max_including_item, max_excluding_item);
                        }
                    }
                }
        

        【讨论】:

          【解决方案16】:
          public static int maxSumNoAdj(int[] nums){
              int[] dp = new int[nums.length];
              dp[0] = Math.max(0, nums[0]); // for dp[0], select the greater value (0,num[0])
              dp[1] = Math.max(nums[1], Math.max(0, dp[0]));    
              int maxSum = Math.max(dp[0], dp[1]);
              for(int i = 2; i < nums.length; i++){
                  int ifSelectCurrent = Math.max(nums[i] + dp[i-2], dp[i-2]);// if select, there are two possible
                  int ifNotSelectCurrent = Math.max(dp[i-1], dp[i-2]);        // if not select, there are two posible
                  dp[i] = Math.max(ifSelectCurrent, ifNotSelectCurrent);      // choose the greater one
                  maxSum = Math.max(dp[i], maxSum);   // update the result
              }
              return maxSum;
          }
          
          public static void main(String[] args) {
              int[] nums = {-9, 2, 3, -7, 1, 1};
              System.out.println(maxSumNoAdj(nums));
          }
          

          【讨论】:

            猜你喜欢
            • 2020-11-01
            • 2016-03-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-03
            • 2021-08-31
            • 1970-01-01
            • 2019-10-05
            相关资源
            最近更新 更多