【问题标题】:How to analysis the time complexity of this code?如何分析这段代码的时间复杂度?
【发布时间】:2016-11-08 00:08:28
【问题描述】:

这是我接受的 Codeforces 问题代码:Education Round 1E

根据经验,我可以自信地解决它,但我总是发现我很难分析这种算法的时间复杂度(通常是 DP 中的递归)

#include<bits/stdc++.h>
using namespace std;

int t;
int N,M,K;
int dp[32][32][52];

int DP(int n, int m, int k){
    if(k > n*m) return 1<<28;
    if(k == n*m || k <= 0) return 0;
    if(dp[n][m][k] != 1<<28) return dp[n][m][k];

    for(int i=1; i<n; i++)
        for(int j=0; j<=k; j++)
            dp[n][m][k] = min(dp[n][m][k],  DP(i, m, j) + DP(n-i, m, k-j) + m*m);

    for(int i=1; i<m;i++)
        for(int j=0; j<=k; j++)
            dp[n][m][k] = min(dp[n][m][k], DP(n, i, j) + DP(n, m-i, k-j) + n*n);

    return dp[n][m][k];
}

int main() {
    cin >> t;

    for(int i=0; i<32;i++) for(int j=0; j<32;j++) for(int k=0; k<52;k++) dp[i][j][k] = 1 << 28;
    while(t--){
        cin >> N >> M >> K;

        cout << DP(N,M,K) << endl;
    }
    return 0;
}

分析DP(N,M,K)之类的函数复杂度的常见做法是什么?我不认为主定理可以在这里应用,因为每个子问题的大小都不相同(但我不确定)。

【问题讨论】:

    标签: recursion time-complexity c++14 dynamic-programming code-analysis


    【解决方案1】:

    你必须解决 dp 矩阵。考虑自下而上。如果你必须计算 dp[n][m][k] 的值,那么它的所有子问题都已经解决了。然后,计算该值所需的时间将是 max(n,m)*k。总体而言,您必须计算 n*m*k 个这样的值。因此,整体时间复杂度将是 O(n*m*k*max(n,m)*k)

    【讨论】:

    • 谢谢,这是有道理的,但是这种分析方法/心态是否适用于所有 DP 问题?
    • 无论你是自上而下还是自下而上,动态规划解的时间复杂度都是一样的。所以是的,您可以使用这种方法来计算 DP 解决方案的一般时间复杂度。
    【解决方案2】:

    (发表另一个可能有帮助的想法)

    和同学讨论后,他提出了一个很简单的想法:

    把递归想象成一个简单的 DFS

    那么复杂度是O(|V| + |E|)

    这里|V| = nmk, |E| = |V|(nk+mk)

    所以总复杂度是O(nmk + n^2mk^2 + nm^2k^2) = O(max(n,m)*nmk^2)

    我喜欢这种建模,但我不确定这是针对此类 DP 解决方案的通用分析方法,因此我接受 @VikramBishnoi 的答案,它最终给出了相同的复杂性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-18
      • 1970-01-01
      • 1970-01-01
      • 2019-09-27
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      相关资源
      最近更新 更多