给定两个正整数N和C 。有一个 2*N 矩阵,其中矩阵的每个单元格都可以用 0 或 1 着色。任务是找到多种方法,2*N 矩阵形成具有恰好 c 个分量。
A cell is said to be in the same component with the other cell if it shares a side with the other cell (immediate neighbor) and is of the same color.
例子:
Input: N = 2, C = 1
Output: 2
Explanation:
C = 1 can be possible when all the cells of the matrix are colored in the same color.
We have 2 choices for coloring 0 and 1. Hence the answer is 2.
Input: N = 1, C = 2
Output: 2
方法:解决这个问题的想法是使用动态规划。构造一个 4D DP 矩阵大小,其中 N 是列数,C 是组件数,2*2 维是最后一列的排列。最后一列可以有四种不同的组合。它们是 00、01、10、11。
矩阵dp[i][j][row1][row2] 的每个单元格给出了当最后一列的排列为 row1、row2 时,在 i 列中具有 j 个分量的方式数。如果当前子问题已被评估,即 dp[column][component][row1][row2] != -1,则使用此结果,否则递归计算该值。
- 基本情况:当列数大于 N 时,返回 0。如果列数等于 N,则答案取决于组件的数量。如果分量等于 C,则返回 1,否则返回 0。
- 情况 1 :当前一列在其行中具有相同的颜色({0, 0} 或 {1, 1})时。
在这种情况下,如果当前列在其行中具有不同的值({0, 1} 或 {1, 0}),则组件将增加 1。如果当前列具有相反的颜色但其行中的值相同,则组件也将增加 1。即当前一列具有 {0, 0} 时,当前列具有 {1, 1}。或者当前一列有 {1, 1} 时,当前列有 {0, 0} 。当前列与前一列的组合相同时,组件保持不变。 - 情况 2 :当前一列在其行中具有不同的颜色({0, 1} 或 {1, 0})时。
在这种情况下,如果当前列的组合与其前一列的组合完全相反,则组件将增加 2。即当前列为 {1, 0} 且上一列为 {0, 1} 时。或者当前列是 {0, 1} ,前一列是 {1, 0} 。在所有其他情况下,组件保持不变。
下面是上述方法的实现:
C++
// C++ implementation to find the
// number of ways to make exactly
// C components in a 2 * N matrix
#include
using namespace std;
// row1 and row2 are one
// when both are same colored
int n, k;
int dp[1024][2048][2][2];
// Function to find the number of
// ways to make exactly C components
// in a 2 * N matrix
int Ways(int col, int comp,
int row1, int row2)
{
// if No of components
// at any stage exceeds
// the given number
// then base case
if (comp > k)
return 0;
if (col > n) {
if (comp == k)
return 1;
else
return 0;
}
// Condition to check
// if already visited
if (dp[col][comp][row1][row2] != -1)
return dp[col][comp][row1][row2];
// if not visited previously
else {
int ans = 0;
// At the first column
if (col == 1) {
// color {white, white} or
// {black, black}
ans
= (ans
+ Ways(col + 1, comp + 1, 0, 0)
+ Ways(col + 1, comp + 1, 1, 1));
// Color {white, black} or
// {black, white}
ans
= (ans
+ Ways(col + 1, comp + 2, 0, 1)
+ Ways(col + 1, comp + 2, 1, 0));
}
else {
// If previous both
// rows have same color
if ((row1 && row2)
|| (!row1 && !row2)) {
// Fill with {same, same} and
// {white, black} and {black, white}
ans = (((ans
+ Ways(col + 1, comp + 1, 0, 0))
+ Ways(col + 1, comp + 1, 1, 0))
+ Ways(col + 1, comp + 1, 0, 1));
// Fill with same without
// increase in component
// as it has been
// counted previously
ans = (ans
+ Ways(col + 1, comp, 1, 1));
}
// When previous rows
// had {white, black}
if (row1 && !row2) {
ans = (((ans
+ Ways(col + 1, comp, 0, 0))
+ Ways(col + 1, comp, 1, 1))
+ Ways(col + 1, comp, 1, 0));
ans = (ans
+ Ways(col + 1, comp + 2, 0, 1));
}
// When previous rows
// had {black, white}
if (!row1 && row2) {
ans = (((ans
+ Ways(col + 1, comp, 0, 0))
+ Ways(col + 1, comp, 1, 1))
+ Ways(col + 1, comp, 0, 1));
ans = (ans
+ Ways(col + 1, comp + 2, 1, 0));
}
}
// Memoization
return dp[col][comp][row1][row2] = ans;
}
}
// Driver Code
signed main()
{
n = 2;
k = 1;
memset(dp, -1, sizeof(dp));
// Initially at first column
// with 0 components
cout << Ways(1, 0, 0, 0);
return 0;
}
Java
// Java implementation to find the
// number of ways to make exactly
// C components in a 2 * N matrix
class GFG{
// row1 and row2 are one
// when both are same colored
static int n, k;
static int [][][][]dp = new int[1024][2048][2][2];
// Function to find the number of
// ways to make exactly C components
// in a 2 * N matrix
static int Ways(int col, int comp,
int row1, int row2)
{
// if No of components
// at any stage exceeds
// the given number
// then base case
if (comp > k)
return 0;
if (col > n)
{
if (comp == k)
return 1;
else
return 0;
}
// Condition to check
// if already visited
if (dp[col][comp][row1][row2] != -1)
return dp[col][comp][row1][row2];
// if not visited previously
else
{
int ans = 0;
// At the first column
if (col == 1)
{
// color {white, white} or
// {black, black}
ans = (ans + Ways(col + 1, comp + 1, 0, 0) +
Ways(col + 1, comp + 1, 1, 1));
// Color {white, black} or
// {black, white}
ans = (ans + Ways(col + 1, comp + 2, 0, 1) +
Ways(col + 1, comp + 2, 1, 0));
}
else
{
// If previous both
// rows have same color
if ((row1 > 0 && row2 > 0) ||
(row1 == 0 && row2 ==0))
{
// Fill with {same, same} and
// {white, black} and {black, white}
ans = (((ans +
Ways(col + 1, comp + 1, 0, 0)) +
Ways(col + 1, comp + 1, 1, 0)) +
Ways(col + 1, comp + 1, 0, 1));
// Fill with same without
// increase in component
// as it has been
// counted previously
ans = (ans +
Ways(col + 1, comp, 1, 1));
}
// When previous rows
// had {white, black}
if (row1 > 0 && row2 == 0)
{
ans = (((ans +
Ways(col + 1, comp, 0, 0)) +
Ways(col + 1, comp, 1, 1)) +
Ways(col + 1, comp, 1, 0));
ans = (ans +
Ways(col + 1, comp + 2, 0, 1));
}
// When previous rows
// had {black, white}
if (row1 ==0 && row2 > 0)
{
ans = (((ans +
Ways(col + 1, comp, 0, 0)) +
Ways(col + 1, comp, 1, 1)) +
Ways(col + 1, comp, 0, 1));
ans = (ans +
Ways(col + 1, comp + 2, 1, 0));
}
}
// Memoization
return dp[col][comp][row1][row2] = ans;
}
}
// Driver Code
public static void main(String[] args)
{
n = 2;
k = 1;
for (int i = 0; i < 1024; i++)
for (int j = 0; j < 2048; j++)
for (int k = 0; k < 2; k++)
for (int l = 0; l < 2; l++)
dp[i][j][k][l] = -1;
// Initially at first column
// with 0 components
System.out.print(Ways(1, 0, 0, 0));
}
}
// This code is contributed by Rajput-Ji
C#
// C# implementation to find the
// number of ways to make exactly
// C components in a 2 * N matrix
using System;
class GFG{
// row1 and row2 are one
// when both are same colored
static int n, k;
static int [,,,]dp = new int[ 1024, 2048, 2, 2 ];
// Function to find the number of
// ways to make exactly C components
// in a 2 * N matrix
static int Ways(int col, int comp,
int row1, int row2)
{
// If No of components
// at any stage exceeds
// the given number
// then base case
if (comp > k)
return 0;
if (col > n)
{
if (comp == k)
return 1;
else
return 0;
}
// Condition to check
// if already visited
if (dp[ col, comp, row1, row2 ] != -1)
return dp[ col, comp, row1, row2 ];
// If not visited previously
else
{
int ans = 0;
// At the first column
if (col == 1)
{
// color {white, white} or
// {black, black}
ans = (ans + Ways(col + 1, comp + 1, 0, 0) +
Ways(col + 1, comp + 1, 1, 1));
// Color {white, black} or
// {black, white}
ans = (ans + Ways(col + 1, comp + 2, 0, 1) +
Ways(col + 1, comp + 2, 1, 0));
}
else
{
// If previous both
// rows have same color
if ((row1 > 0 && row2 > 0) ||
(row1 == 0 && row2 == 0))
{
// Fill with {same, same} and
// {white, black} and {black, white}
ans = (((ans +
Ways(col + 1, comp + 1, 0, 0)) +
Ways(col + 1, comp + 1, 1, 0)) +
Ways(col + 1, comp + 1, 0, 1));
// Fill with same without
// increase in component
// as it has been
// counted previously
ans = (ans +
Ways(col + 1, comp, 1, 1));
}
// When previous rows
// had {white, black}
if (row1 > 0 && row2 == 0)
{
ans = (((ans +
Ways(col + 1, comp, 0, 0)) +
Ways(col + 1, comp, 1, 1)) +
Ways(col + 1, comp, 1, 0));
ans = (ans +
Ways(col + 1, comp + 2, 0, 1));
}
// When previous rows
// had {black, white}
if (row1 == 0 && row2 > 0)
{
ans = (((ans +
Ways(col + 1, comp, 0, 0)) +
Ways(col + 1, comp, 1, 1)) +
Ways(col + 1, comp, 0, 1));
ans = (ans +
Ways(col + 1, comp + 2, 1, 0));
}
}
// Memoization
return dp[ col, comp, row1, row2 ] = ans;
}
}
// Driver Code
public static void Main(String[] args)
{
n = 2;
k = 1;
for(int i = 0; i < 1024; i++)
for(int j = 0; j < 2048; j++)
for(int K = 0; K < 2; K++)
for(int l = 0; l < 2; l++)
dp[ i, j, K, l ] = -1;
// Initially at first column
// with 0 components
Console.Write(Ways(1, 0, 0, 0));
}
}
// This code is contributed by Rajput-Ji
2
时间复杂度:O(N*C)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。