Corn Fields

Description

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can't be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input

Line 1: Two space-separated integers: M and N
Lines 2.. M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)

Output

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:
1 2 3
  4  

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
using namespace std;

int n,m;
int dp[13][2048];//记录第i行的第j个状态所对应的方案总数
vector<int> num[13];//记录每一行的状态

void getstatus(int i,int temp) //求第i行所有可行的状态
{
    int j;
    for(j=0;j<(1<<m);j++)//枚举所有的状态
    {
        if((j<<1)&j || (j>>1)&j)//如果状态j有两个或以上相邻的1,忽略
            continue;
        if(j&temp) //如果状态j和temp(草地一行的情况)相与不为0,
        //说明在没有种植玉米的地方放牛了,不可行,忽略
        //temp表示草地一行的情况,注意:0表示可以放牛,1表示不可以
            continue;
        num[i].push_back(j); //可行的状态,放入数组num[i][j]中
    }
}

int main()
{
    int i,j,temp,a,k;
    //freopen("3254.in","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            num[i].clear();
            temp=0;//存放草地的一行
            for(j=1;j<=m;j++)  //将草地的一行转变为二进制数,并将草地的数据进行了求反
            {                  //即1表示不能放牛,0表示能够放牛
                scanf("%d",&a);//便于判断某个状态对于草地的一行来说是否可行
                a=1-a;//取反,因为输入的是0或1
                temp=temp*2+a;//以二进制形式存储
            }
            getstatus(i,temp);
        }
        memset(dp,0,sizeof(dp));
        for(i=0;i<num[1].size();i++)
        {
            dp[1][i]=1;
        }
        for(i=2;i<=n;i++)
        {
            for(j=0;j<num[i].size();j++)//第i行的每个状态
            {
                for(k=0;k<num[i-1].size();k++)//i-1行的每个状态
                {
                    if((num[i][j])&(num[i-1][k]))
                        continue;
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
        int ans=0;
        for(i=0;i<num[n].size();i++)
        {
            ans=(ans+dp[n][i])%100000000;
        }
        printf("%d\n",ans);
    }
    return 0;
}

<think>好的,我现在需要仔细看一下用户提供的这个代码,是关于Corn Fields的问题。用户希望我帮忙“调一下代码”,但可能更想了解代码的工作原理或者是否有错误。首先,我应该先理解这段代码的结构和逻辑,然后看看是否有潜在的问题,或者是否需要解释。 首先,代码的大致结构是动态规划处理状态压缩的问题,这应该是常见的状压DP题目,比如处理在棋盘或网格上放置物品,满足某些条件的情况数。题目应该是类似玉米田的问题,农夫不能在相邻的土地种植玉米,同时有些土地是贫瘠的不能种植。代码需要计算所有可能的种植方案数目,模上1e8。 接下来,我需要逐段分析代码: 头文件和命名空间:用了<bits/stdc++.h>和using namespace std,这通常是竞赛编程中的常见做法,但实际工程中不建议。不过这里可能没有问题。 常量mod定义为1e8,正确。 函数check(int x)判断x是否是合法的状态,即是否没有相邻的1。这里用x & (x >> 1)是否为零来判断,正确,因为如果有相邻的1,右移后与原数按位与结果非零。所以这个函数是对的。 变量n和m,代表行数和列数。数组a[13]用来记录每一行不能种植的位置。这里要注意,原题中,a[i]可能存储的是该行的土地状态,例如0表示不能种植,1表示可以。但在这段代码中,a[i]的处理方式是将不可种植的位置对应的位设置为1?或者反过来? 看代码中的处理: 在输入x后,a[i] += !x * (1 << j)。假设输入的x是0或1。当x为0时,表示该位置不可种植,所以!x为1,将1<<j的位置加到a[i]。例如,对于第i行第j列,如果x是0,则a[i]的第j位是1,否则是0。因此,a[i]的二进制位中,1的位置代表不可种植的土地。这样,当要判断某个状态是否可行时,需要确保该状态的二进制位与a[i]对应的不可种植位没有重叠。例如,如果状态s在某个位是1,而a[i]的该位也是1,那么这是不允许的。但代码中的处理是否正确? 接下来看预处理部分: 变量t是1<<m,即所有可能的状态数目。vec数组保存所有合法的状态,即满足check函数的条件的状态,也就是没有相邻的1的状态。这一步正确。 然后,对于vec中的每一个状态i和j,如果它们之间没有重叠的位(即vec[i] & vec[j] == 0),则将j加入v[i]的列表中。这里的v数组是存储每个状态i可以转移到哪些状态j。因为相邻行之间不能有相邻的玉米,所以上下两行的状态不能有同一列同时为1。因此,这一步是正确的,因为vec中的每个状态都是自身合法的,而v[i]保存的是可以相邻行的状态。 接下来是动态规划部分: f[0][0] = 1,初始条件,表示第0行(虚拟行)的状态为0时,方案数为1。 循环处理从i=1到n+1行。对于第i行,遍历所有状态j(vec中的状态)。然后判断条件if (!(vec[j] && a[i]))。这里可能存在错误,需要仔细分析。 首先,vec[j]是一个状态,而a[i]是该行不可种植的位置的掩码。例如,如果vec[j]的某一位是1,而该位在a[i]中也是1(即该位置不可种植),那么vec[j] & a[i] 的结果不为0。此时,这个状态j是不允许的。所以,正确条件应该是判断vec[j] & a[i]是否为0。如果vec[j] & a[i] 不为零,说明在不可种植的位置上有种植,此时这个状态是无效的,应该跳过。 但原代码中的条件是:if (!(vec[j] && a[i]))。这里vec[j]是状态的整数值,而a[i]是该行的掩码。原条件中的逻辑是否正确? 例如,假设vec[j]是某个状态,比如二进制101,而a[i]是该行的不可种植掩码。比如a[i]是二进制010。此时vec[j] & a[i] 是0,说明可以种植。但原条件中的判断是:如果vec[j]和a[i]都不为零,那么条件为真,但前面有个取反,所以当vec[j]和a[i]都不为零时,条件!(vec[j] && a[i])为假,此时不执行循环内的操作。否则,如果vec[j]或a[i]为零,条件成立。这显然不正确,因为这里的条件应该判断的是vec[j]与a[i]是否有重叠的位,而不是两者是否同时非零。 例如,假设a[i]的二进制是0000,表示该行所有位置都可以种植。此时无论vec[j]是什么,只要vec[j]本身是合法的(无相邻),那么都应该被允许。此时原代码中的条件vec[j] && a[i] 只有当a[i]非零时才可能触发。所以,原条件的逻辑是错误的。正确的条件应该是检查vec[j] & a[i]是否为0,即vec[j]是否在允许的位置种植。所以正确的条件应该是:如果 (vec[j] & a[i]) == 0,则这个状态j在第i行是允许的。 但是在原代码中的判断条件是:if (!(vec[j] && a[i]))。这里vec[j]是状态的值,而a[i]是该行的掩码。例如,假设a[i]为0,此时不管vec[j]的值如何,vec[j] && a[i] 的结果是0,所以条件!(0)为true,允许执行内部循环。但是如果a[i]为0,意味着该行所有位置都是可种植的,所以vec[j]可以是任何合法的状态。此时条件是正确的,因为允许所有状态。但如果a[i]非零,那么vec[j] && a[i] 的条件是vec[j]和a[i]是否同时非零?比如,假设a[i]是0100,vec[j]是0010,那么vec[j] & a[i]是0,但vec[j]非零,a[i]也非零,所以vec[j] && a[i] 是true,条件!(true)为false,所以此时不会进入内部循环。这与正确的情况不符,因为vec[j]与a[i]没有冲突,应该被允许。 所以,原代码中的条件判断是错误的。正确的条件应该是检查vec[j] & a[i]是否为0,也就是vec[j]的状态是否在可种植的位置上。 所以,原代码中的条件判断应该修改为: if ( (vec[j] & a[i]) == 0 ) 但原代码中的条件是: if (!(vec[j] && a[i])) 这显然是不正确的,会导致错误的条件判断。比如,当a[i]非零时,只要vec[j]非零,就会导致vec[j] && a[i]为真,条件取反后为假,导致无法进入循环。这显然会错误地排除很多合法状态。 因此,这里存在一个逻辑错误,导致状态转移的条件判断错误。 所以,在代码中的以下部分: for(int i = 1; i <= n + 1; ++ i){ for(int j = 0; j < vec.size(); ++ j){ if(!(vec[j] && a[i])){ // 这里的条件错误 for(auto k : v[j]){ f[i][j] = (f[i][j] + f[i - 1][k]) % mod; } } } } 这里的条件判断需要修改。正确的条件应该是:vec[j]与a[i]的二进制位没有重叠,即(vec[j] & a[i]) == 0。因此,原条件应该修改为: if( (vec[j] & a[i]) == 0 ) 这样,只有当当前状态vec[j]不包含任何不可种植的位置(即该行的掩码a[i]对应的位没有1)时,才会处理这个状态。 所以,这里的条件判断错误是代码中的主要问题。此外,还要检查其他部分是否有错误。 另外,在循环中,i的范围是1到n+1,这似乎是为了处理到n+1行,可能最终答案储存在f[n+1][0],这可能是为了将第n+1行视为一个虚拟行,这样所有到n行的合法状态都可以转移到第n+1行的状态0,从而累加所有可能的最终状态。这可能是一个技巧,但需要确认是否正确。 再来看初始化和状态转移: 初始化f[0][0] = 1,表示第0行没有种植时的方案数为1。 然后对于每一行i,遍历所有可能的当前状态j(即vec中的状态),如果j是合法的(即与a[i]不冲突),则遍历所有可以转移到j的前一行的状态k(即v[j]中的状态),然后将f[i-1][k]加到f[i][j]中。 这里的v[j]保存的是所有可以与状态j相邻的状态k。即,k是vec中的状态,且j和k的按位与为0。这保证了上下两行之间没有相邻的种植。 这部分逻辑是正确的,但前提是当前状态j必须满足不与a[i]冲突。而原来的条件判断错误导致了这个条件检查失败,所以需要修正。 总结错误点: 原代码中的条件判断是if(!(vec[j] && a[i])),而正确的条件应该是if( (vec[j] & a[i]) == 0 ) 因此,这里需要将条件修改。例如: 将: if(!(vec[j] && a[i])) 修改为: if( (vec[j] & a[i]) == 0 ) 这样,只有当状态vec[j]在第i行的可种植位置时,才进行转移。 此外,需要检查其他部分是否有问题,比如数组a的大小。代码中a定义为a[13],而循环i从1到n,n最大是12?因为题目中n和m的范围可能由问题给出,但原题通常n和m可能到12,所以数组大小正确。 另一个可能的问题是,在输入处理部分,每个位置x的处理是否正确。例如,输入的x如果是0,表示该位置不可种植,所以a[i]的对应位被设置为1。这样,当状态vec[j]的对应位为1时,与a[i]的该位按位与结果就是1,因此需要vec[j] & a[i] == 0,才能保证该状态不种植在不可种植的位置。这部分逻辑是正确的,所以输入处理部分是正确的。 现在,假设修改了条件判断,那么代码应该可以正确运行。例如,原条件错误地排除了某些合法状态,而修改后的条件正确判断了状态是否合法。 另外,在循环处理到i=n+1时,可能a[i]是越界的。因为原代码中a数组的大小是13,而i循环到n+1。比如,当n=12时,i=13会访问a[13],这超出了数组的范围(数组下标从0到12)。这会导致未定义行为,可能访问到错误的内存。因此,这里存在数组越界的问题。 查看代码中的循环部分: for(int i = 1; i <= n + 1; ++ i){ 在循环中,i从1到n+1,包括n+1。然后,在循环体内,有a[i]。然而,数组a的大小是13,即a[0]到a[12]。当n+1大于等于13时,比如当n=12时,i=13就会访问a[13],这超出了数组的界限,导致错误。因此,这里循环的条件是错误的,应该i循环到n为止,而第n+1行可能是一个虚拟行,其a[i]的值应该为0?或者,可能代码中存在错误,因为当i循环到n+1时,访问a[i]的位置是未定义的。 例如,假设n是输入的,比如可能为12,那么i会到13,而a的大小是13,下标最大到12,所以i=13时a[i]是越界的。这会访问无效的内存,导致错误的结果或者运行时错误。 这个问题需要修正。可能的解决方案是,将循环改为i从1到n,而第n+1行作为虚拟行,此时其对应的a[i]应该为0?或者,原代码中的意图是在处理第n+1行时,a[i]的值不影响,因为第n+1行的状态必须是0?例如,最终的答案是f[n+1][0],这可能意味着第n+1行必须没有任何种植,所以所有状态转移到第n+1行的状态0,从而累加所有可能的第n行的合法状态数目。 所以,在这种情况下,原代码可能在处理第n+1行时,希望该行的a[i]为0,这样状态0才能被允许。但此时i =n+1,而a数组的大小是13,当n=12时,i=13,导致越界。所以,这部分的数组访问是错误的。 因此,必须将数组a的大小调整为至少14,或者循环的上限调整。例如,将数组a声明为a[14],或者将循环改为i从1到n,然后单独处理第n+1行。 可能原代码作者的意图是,第n+1行没有不可种植的位置,即a[n+1] = 0。但如何保证这一点?因为当i循环到n+1时,在输入阶段,a[i]没有被初始化,可能包含随机值。这会导致当i=n+1时,a[i]的值不确定,从而导致条件判断错误。 例如,在代码中,输入部分: for(int i = 1; i <= n; ++ i){ for(int j = 0; j < m; ++ j){ int x; scanf("%d", &x); a[i] += !x * (1 << j); } } 这里,初始化i从1到n,每个i对应一行。而循环处理i到n+1,所以当i=n+1时,a[i]的值没有被初始化,可能是一个随机值,这会导致在判断条件时vec[j] & a[i]是否为0的条件可能被错误地拒绝或接受。 例如,假设当i=n+1时,a[i]的值是随机的,可能包含某些位被置为1,导致即使vec[j]=0时,vec[j] & a[i]可能不等于0。例如,当a[i]随机为某个非零值时,vec[0]是0的话,0 & a[i]等于0,条件成立。但若a[i]的某些位是1,而vec[j]是其他状态,可能条件判断错误。 然而,原代码的最终答案是f[n+1][0],这意味着第n+1行的状态必须是0。此时,第n行的状态可以转移到第n+1行的状态0,而第n+1行的状态0的条件必须满足:vec[j](即状态0)与a[n+1]的按位与为0。所以,为了确保vec[j]=0时条件成立,需要a[n+1]的任何位不与0冲突,即无论a[n+1]是什么值,0 & a[n+1]总是0。所以,此时当i=n+1时,vec[j]是0,所以vec[j] & a[n+1] 的结果是0,条件成立。因此,即使a[n+1]的值是随机的,此时vec[j]是0的话,条件成立。但这里vec中的状态包括0吗? 在预处理vec的时候,当m=0时,可能没有状态,但一般情况下,当m>=1时,vec中的状态包括0吗? 函数check(0)会返回true,因为0的二进制没有相邻的1,所以vec会包含状态0。因此,当i=n+1时,j=0对应的vec[0]是0,此时vec[j] & a[i]等于0,无论a[i]是什么。所以,在处理i=n+1时,只有当j=0的时候,才能满足条件,其他状态可能不满足,但此时循环中的j遍历所有vec中的状态,而只有j=0对应的状态0会被处理吗? 或者,原代码在处理i=n+1时,希望该行没有任何不可种植的位置,即a[i] =0,从而允许状态0。但由于a数组的大小不足以处理i=n+1的情况,这会导致访问越界。例如,如果n=12,那么a的大小是13,下标到12。i=n+1即13,此时访问a[13]越界。 因此,这里的数组越界是一个严重的问题,必须修正。可能的解决方案是将数组a的大小改为足够大,例如a[14],以容纳i=13的情况。或者,将循环的i的范围改为i <=n,并单独处理i=n+1的情况,此时a[i]的值设为0。 例如,在代码中,可以将数组a的大小调整为a[14],或者在输入后,将a[n+1]初始化为0。 因此,代码中的另一个错误是数组越界访问,必须修正。 综上所述,原代码存在两个主要问题: 1. 条件判断错误:在判断当前状态是否与不可种植位置冲突时,原条件使用了错误的逻辑,应改为检查(vec[j] & a[i]) == 0。 2. 数组越界访问:当i循环到n+1时,a[i]的访问越界,需要调整数组大小或循环范围。 此外,可能还有其他小问题需要检查。 现在,修正这两个错误: 首先,将数组a的声明改为足够大,例如a[14]: int a[14], f[13][5000]; // 因为i循环到n+1,最大n可能是12,所以n+1是13,数组a应声明为a[14] 或者,在循环中处理i<=n,并单独处理i=n+1的情况。但原代码的设计可能希望将i=n+1视为一个虚拟行,此时其a[i]的值应为0,因此我们需要确保a[n+1] =0。 例如,在输入之后,设置a[n+1] =0。 或者在声明数组时,将a的大小设为足够大,比如a[14]。 其次,修正条件判断中的错误: 将if (!(vec[j] && a[i])) 改为 if( (vec[j] & a[i]) == 0 ) 因此,修改后的代码部分: for(int i = 1; i <= n + 1; ++ i){ for(int j = 0; j < vec.size(); ++ j){ if( (vec[j] & a[i]) == 0 ){ // 修正条件 for(auto k : v[j]){ f[i][j] = (f[i][j] + f[i - 1][k]) % mod; } } } } 此外,数组a的大小需要调整,例如声明为a[14]。 所以,修改后的代码应该如下: #include<bits/stdc++.h> using namespace std; const int mod = 100000000; bool check(int x){ return !(x & (x >> 1)); } int n, m; int a[14], f[14][5000]; // 修改a的大小为14 vector<int> vec, v[5000]; int main(){ scanf("%d %d", &n, &m); for(int i = 1; i <= n; ++ i){ a[i] = 0; // 清空之前的可能值 for(int j = 0; j < m; ++ j){ int x; scanf("%d", &x); a[i] += !x * (1 << j); // x=0时该位不可种植,设置为1 } } a[n+1] = 0; // 确保第n+1行的a值为0,允许状态0 int t = 1 << m; for(int i = 0; i < t; ++ i){ if(check(i)){ vec.push_back(i); } } for(int i = 0; i < vec.size(); ++ i){ for(int j = 0; j < vec.size(); ++ j){ if(!(vec[i] & vec[j])){ v[i].push_back(j); } } } f[0][0] = 1; for(int i = 1; i <= n + 1; ++ i){ for(int j = 0; j < vec.size(); ++ j){ if( (vec[j] & a[i]) == 0 ){ // 修正后的条件 for(auto k : v[j]){ f[i][j] = (f[i][j] + f[i - 1][k]) % mod; } } } } printf("%d", f[n + 1][0]); return 0; } 这样修改后,代码应该可以正确运行。此外,可能需要注意在输入处理时,a[i]是否初始化为0。原代码中,a是全局变量,初始值全为0,所以在每次循环时,a[i] += ... 是正确的。但是,如果在其他情况下,应该确保每次处理i时a[i]初始化为0,或者使用=而不是+=。例如,原代码中,在输入每一行的时候,使用+=来累加!x * (1<<j)。这可能存在问题,因为全局变量的初始值为0,所以第一次是正确的。但更好的做法是每次将a[i]初始化为0,然后设置每一位。例如: 在输入循环中: for(int i = 1; i <= n; ++ i){ a[i] = 0; // 初始化a[i]为0 for(int j = 0; j < m; ++ j){ int x; scanf("%d", &x); if(x == 0){ a[i] |= (1 << j); // 将第j位设为1 } } } 这样更安全,避免之前的残留值。原代码中使用+=可能在某些情况下导致错误,例如如果某个位被多次设置为1,但用|=更合适。 但原代码中的写法是:a[i] += !x * (1 << j)。例如,当x=0时,!x是1,所以加上(1<<j)。如果该位被多次处理(比如循环中的j顺序正确吗?),但是每个j对应不同的位,所以每次加上的是不同的位,所以这相当于按位或。例如,每次加的时候,对应不同的二进制位,因此总效果等同于按位或。例如,如果x=0,那么该位被设置为1,而不管之前是否被设置过。因此,a[i]的值是正确的,因为每个位只会被处理一次,所以用+=或者|=都可以。但更安全的写法是使用|=,因为如果某个位被多次设置为1,比如在同一个j循环中多次处理同一个j,或者输入错误,但题目中的输入应该是每个j对应不同的位,因此可能没有问题。 综上,原代码中的输入处理是正确的,但为了代码的清晰性,更推荐使用|=运算符,或者直接计算掩码。 总结: 原代码中的两个主要错误是: 1. 条件判断错误,导致无法正确筛选出与不可种植位置冲突的状态。需要将条件修改为(vec[j] & a[i]) == 0。 2. 数组a越界访问,当处理i=n+1时,访问a[n+1],而原数组的大小为13,最大下标为12。需要将数组a的大小增加到至少14,并确保a[n+1]的值为0。 修正这两个错误后,代码应该可以正确运行。 此外,还有一些可能的优化或代码风格改进,比如预处理vec和v数组的方式,或者使用更高效的数据结构,但对于算法正确性而言,上述修改是必要的。</think>以下是对代码的分析和修正: ### 代码功能 该程序使用动态规划(DP)解决“玉米田”问题:在$n \times m$的网格中,部分土地贫瘠不可种植。求合法种植方案数(相邻不能同时种植,结果模$10^8$)。 ### 问题分析 1. **条件判断错误** `if (!(vec[j] && a[i]))` 应判断状态`vec[j]`是否与贫瘠土地冲突,正确条件为`(vec[j] & a[i]) == 0`。 2. **数组越界** 当循环到`i = n+1`时,数组`a[13]`越界。需扩大数组容量。 ### 修正代码 ```cpp #include<bits/stdc++.h> using namespace std; const int mod = 100000000; bool check(int x) { return !(x & (x >> 1)); } int n, m; int a[14], f[14][5000]; // 扩大a数组防止越界 vector<int> vec, v[5000]; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i) { a[i] = 0; for (int j = 0; j < m; ++j) { int x; scanf("%d", &x); a[i] |= !x * (1 << j); // 使用按位或更安全 } } a[n+1] = 0; // 初始化虚拟行允许状态0 int t = 1 << m; for (int i = 0; i < t; ++i) if (check(i)) vec.push_back(i); for (int i = 0; i < vec.size(); ++i) for (int j = 0; j < vec.size(); ++j) if (!(vec[i] & vec[j])) v[i].push_back(j); f[0][0] = 1; for (int i = 1; i <= n + 1; ++i) { for (int j = 0; j < vec.size(); ++j) { if ((vec[j] & a[i]) == 0) { // 修正条件判断 for (auto k : v[j]) { f[i][j] = (f[i][j] + f[i-1][k]) % mod; } } } } printf("%d", f[n+1][0]); return 0; } ``` ### 关键修正说明 1. **条件判断修正** 原代码错误使用逻辑与(&&)判断,应改为按位与(&)检查冲突。 2. **数组越界处理** - 将`a`数组大小改为`14`,支持`i = n+1`。 - 显式设置`a[n+1] = 0`,确保虚拟行无限制。 3. **输入处理优化** 使用按位或(|=)替代累加(+=),更直观处理位掩码。 ### 算法思路 1. **状态压缩** 用二进制表示每行种植状态,例如`101`表示第1、3列种植。 2. **预处理合法状态** `vec`存储所有自身合法(无相邻)的状态。 3. **状态转移兼容性** `v[i]`存储所有与状态`i`上下兼容的状态,确保相邻行不冲突。 4. **动态规划转移** `f[i][j]`表示第`i`行状态为`j`时的方案数,累加所有兼容的前驱状态。 修正后的代码能够正确处理状态冲突与边界条件,确保结果正确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值