查找使用1,2,3,4创建的数字的数量,使得相同的数字永远不会在一起

时间:2014-10-17 13:51:30

标签: algorithm dynamic-programming

  

有一个特定的序列只使用数字1,2,3,4并且没有两个相邻的数字是相同的   编写一个给出n1 1s,n2 2s,n3 3s,n4 4s的程序将使用所有这些数字输出这些序列的数量。
  输出您的答案模1000000007(10 ^ 9 + 7)。

我在geeksforgeeks.com上发现了这个问题。

打印所有此类解决方案的天真方法将花费O(4 ^ n)。使用动态编程可以有更好的解决方案吗?

我尝试为DP运行以下代码。给出了错误的答案。有人可以建议改进吗?

#include<iostream>
using namespace std;

int d1[50][50][50][50],d2[50][50][50][50],d3[50][50][50][50],d4[50][50][50][50];

int main(){
    int n1,n2,n3,n4;
    n1=2;n2=2;n3=1;n4=2;
    d1[1][0][0][0]=1;
    d2[0][1][0][0]=1;
    d3[0][0][1][0]=1;
    d4[0][0][0][1]=1;
    for(int i=0;i<=n1;i++){
        for(int j=0;j<=n2;j++){
            for(int k=0;k<=n3;k++){
                for(int l=0;l<=n4;l++){
                    if(i)d1[i][j][k][l]=d2[i-1][j][k][l]+d3[i-1][j][k][l]+d4[i-1][j][k][l];
                    if(j)d2[i][j][k][l]=d1[i][j-1][k][l]+d3[i][j-1][k][l]+d4[i][j-1][k][l];
                    if(k)d3[i][j][k][l]=d2[i][j][k-1][l]+d1[i][j][k-1][l]+d4[i][j][k-1][l];
                    if(l)d4[i][j][k][l]=d2[i][j][k][l-1]+d3[i][j][k][l-1]+d1[i][j][k][l-1];
                }
            }
        }
    }
    cout<<d1[n1][n2][n3][n4]+d2[n1][n2][n3][n4]+d3[n1][n2][n3][n4]+d4[n1][n2][n3][n4];
}

5 个答案:

答案 0 :(得分:3)

请考虑以下事项: 让dpX[i][j][k][l]代表以X结尾的此类序列的数量,X为1,2,3或4,i个,j两个, k三分,l四肢。然后,您将获得dp1的公式:

dp1[i][j][k][l] = dp2[i-1][j][k][l] + dp3[i-1][j][k][l] + dp4[i-1][j][k][l]

类似于dp2dp3dp4。答案是dp1[n1][n2][n3][n4] + dp2[n1][n2][n3][n4] + dp3[n1][n2][n3][n4] + dp4[n1][n2][n3][n4]

时间复杂度为O(n1*n2*n3*n4)

答案 1 :(得分:3)

您的代码需要条件(i + j + k + l> 1)否则它会生成 dp4 [0] [0] [0] [1] = 0.这也适用于其他dpX。

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

int d1[50][50][50][50],d2[50][50][50][50],d3[50][50][50][50],d4[50][50][50][50];

#define MOD 1000000007

int main(){
    int n1,n2,n3,n4;
    scanf("%d%d%d%d", &n1, &n2, &n3, &n4);
    d1[1][0][0][0]=1;
    d2[0][1][0][0]=1;
    d3[0][0][1][0]=1;
    d4[0][0][0][1]=1;
    for(int i=0;i<=n1;i++){
        for(int j=0;j<=n2;j++){
            for(int k=0;k<=n3;k++){
                for(int l=0;l<=n4;l++){
                    if (i + j + k + l > 1) {
                    if(i)d1[i][j][k][l]=d2[i-1][j][k][l]+d3[i-1][j][k][l]+d4[i-1][j][k][l] % MOD;
                    if(j)d2[i][j][k][l]=d1[i][j-1][k][l]+d3[i][j-1][k][l]+d4[i][j-1][k][l] % MOD;
                    if(k)d3[i][j][k][l]=d2[i][j][k-1][l]+d1[i][j][k-1][l]+d4[i][j][k-1][l] % MOD;
                    if(l)d4[i][j][k][l]=d2[i][j][k][l-1]+d3[i][j][k][l-1]+d1[i][j][k][l-1] % MOD;
                }
                }
             }
        }
    }
    cout<<d1[n1][n2][n3][n4]+d2[n1][n2][n3][n4]+d3[n1][n2][n3][n4]+d4[n1][n2][n3][n4] % MOD << endl;
}

答案 2 :(得分:1)

以下方法使用4维数组来存储没有相邻的特定序列的数量。

dp1 [i] [j] [k] [l]:没有相邻末端的特定序列的数量为1且具有i 1s,j 2s,k 3s,l 4s。

dp2 [i] [j] [k] [l]:没有相邻末端的特定序列的数量为2,并且具有i 1s,j 2s,k 3s,l 4s。

所以dp1 [i] [j] [k] [l] = dp2 [i - 1] [j] [k] [l] + dp3 [i - 1] [j] [k] [l] + dp4 [i - 1] [j] [k] [l];
dp1将是i - 1 1s与2(dp2),3(dp3),4(dp4)结束的总和;

public int Sequence(int n1, int n2, int n3, int n4)
        {
            var dp1 = new int[n1 + 1, n2 + 1, n3 + 1, n4 + 1];
            var dp2 = new int[n1 + 1, n2 + 1, n3 + 1, n4 + 1];
            var dp3 = new int[n1 + 1, n2 + 1, n3 + 1, n4 + 1];
            var dp4 = new int[n1 + 1, n2 + 1, n3 + 1, n4 + 1];

            const int MOD = 1000000007;
            dp1[1, 0, 0, 0] = 1;
            dp2[0, 1, 0, 0] = 1;
            dp3[0, 0, 1, 0] = 1;
            dp4[0, 0, 0, 1] = 1;

            for (int i = 0; i <= n1; i++)
            {
                for (int j = 0; j <= n2; j++)
                {
                    for (int k = 0; k <= n3; k++)
                    {
                        for (int l = 0; l <= n4; l++)                                        {                             
                            if (i + j + k + l > 1)
                            {
                                if (i > 0) dp1[i, j, k, l] = dp2[i - 1, j, k, l] + dp3[i - 1, j, k, l] + dp4[i - 1, j, k, l] % MOD;
                                if (j > 0) dp2[i, j, k, l] = dp1[i, j - 1, k, l] + dp3[i, j - 1, k, l] + dp4[i, j - 1, k, l] % MOD;
                                if (k > 0) dp3[i, j, k, l] = dp2[i, j, k - 1, l] + dp1[i, j, k - 1, l] + dp4[i, j, k - 1, l] % MOD;
                                if (l > 0) dp4[i, j, k, l] = dp2[i, j, k, l - 1] + dp3[i, j, k, l - 1] + dp1[i, j, k, l - 1] % MOD;
                            }
                        }
                    }

                }
            }
            return dp1[n1, n2, n3, n4] + dp2[n1, n2, n3, n4] + dp3[n1, n2, n3, n4] + dp4[n1, n2, n3, n4] % MOD;
        }

答案 3 :(得分:0)

感谢您的逻辑,但它有一个小错误。当i = 0,j = 0,k = 0,l = 1时,查看第二次迭代本身:我们有d4 [0] [0] [0] [1] = 0.即,基本情况正在被修改,因此答案变为0.这个问题的快速修复可能是在更新所有d再次添加4个基本案例后的最内层循环中。这解决了它。如果有人有任何更好的想法,请对其进行评论。

答案 4 :(得分:0)

以上解决方案不会处理大元素..这个解决方案将适用于所有测试用例。经过测试:)

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int d1[21][21][21][21],d2[21][21][21][21],d3[21][21][21][21],d4[21][21][21][21];

#define MOD 1000000007

int main(){
ll n1,n2,n3,n4;
cin>>n1>>n2>>n3>>n4;
d1[1][0][0][0]=1;
d2[0][1][0][0]=1;
d3[0][0][1][0]=1;
d4[0][0][0][1]=1;
for(int i=0;i<=n1;i++){
    for(int j=0;j<=n2;j++){
        for(int k=0;k<=n3;k++){
            for(int l=0;l<=n4;l++){
                if (i + j + k + l > 1) {
                if(i>0)d1[i][j][k][l]=(d2[i-1][j][k][l] % MOD +d3[i-1][j][k][l]% MOD+d4[i-1][j][k][l]% MOD) % MOD;
                if(j>0)d2[i][j][k][l]=(d1[i][j-1][k][l] % MOD+d3[i][j-1][k][l]% MOD+d4[i][j-1][k][l]% MOD )% MOD;
                if(k>0)d3[i][j][k][l]=(d2[i][j][k-1][l] % MOD+d1[i][j][k-1][l] % MOD+d4[i][j][k-1][l]% MOD) % MOD;
                if(l>0)d4[i][j][k][l]=(d2[i][j][k][l-1] % MOD+d3[i][j][k][l-1] % MOD+d1[i][j][k][l-1]% MOD) % MOD;
            }
            }
         }
    }
}
cout<<(d1[n1][n2][n3][n4]% MOD+d2[n1][n2][n3][n4]% MOD+d3[n1][n2][n3][n4]% MOD+d4[n1][n2][n3][n4]% MOD) % MOD << endl;
}