В определенной последовательности используются только числа 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];
}
2
user2714358 17 Окт 2014 в 17:51
Тут наверное не по теме. Попробуйте задать вопрос на programmers.stackexchange.com или scicomp.stackexchange. .com
 – 
Johnny Mopp
17 Окт 2014 в 17:55
Или, может быть, cs.stackexchange.com. Сейчас их так много, что иногда трудно решить, где публиковать... Но определенно не здесь. Для этого сайта требуется уже написанный, но не работающий код. Я думаю...:)
 – 
Johnny Mopp
17 Окт 2014 в 18:00
В вашем примере вы переписываете dp, который вы инициализировали в цикле. Простой способ решить эту проблему — обновить dp, если i+j+k+l > 1.
 – 
Attila
17 Окт 2014 в 21:11

5 ответов

Лучший ответ

Учтите следующее: пусть 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]

И аналогичные для dp2, dp3 и dp4. Ответом будет <код> 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).

4
Attila 17 Окт 2014 в 18:05
Скажите, как вы будете это реализовывать? Для этого требуются значения dp1, dp2, dp3 и dp4 одновременно. Как вы можете обновлять их одновременно?
 – 
user2714358
17 Окт 2014 в 19:51
Вы можете запустить его в четыре последовательных цикла: по i, j, k и l.
 – 
Attila
17 Окт 2014 в 20:20
Я написал свой код в вопросе. Можете ли вы предложить некоторые изменения? Я начинающий. Простите мои ошибки.
 – 
user2714358
17 Окт 2014 в 20:44
Возможно, вы забыли, что вам нужен ответ mod 1e9+7.
 – 
Attila
17 Окт 2014 в 20:46

Ваш код требует условия (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;
}
3
Vipul Jain 27 Окт 2014 в 20:16

В следующем подходе используются четырехмерные массивы для хранения количества конкретных последовательностей без смежных.

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 единиц, заканчивающихся на 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;
        }
1
GorvGoyl 18 Ноя 2016 в 16:18

Спасибо за логику, но в ней есть небольшая ошибка. Посмотрите на саму вторую итерацию, когда i = 0, j = 0, k = 0, l = 1: мы имеем d4 [0] [0] [0] [1] = 0. т.е. базовый случай изменяется и, следовательно, ответ будет 0. Быстрое решение этой проблемы может быть выполнено во внутреннем цикле после повторного обновления всех базовых случаев d add 4. Это исправляет. Если у кого-то есть идеи получше, прокомментируйте это.

0
Ravi Teja 20 Окт 2014 в 12:23
Итак, вы предлагаете сложить все di [i][j][k][l] и вернуть общую сумму после всех итераций? Я добавил t+=d1[i][j][k][l]+d2[i][j][k][l]+d3[i][j][k][l]+d4[i] [ж] [к] [л]; утверждение. Но все же это не работает.
 – 
user2714358
21 Окт 2014 в 10:46

Вышеупомянутое решение не будет обрабатываться для больших элементов .. это решение будет работать со всеми тестовыми примерами .. Протестировано :)

#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;
}
0
Rohit Jain 20 Мар 2017 в 19:57