uva11464 - Even Parity

应该是属于暴力枚举类型的题目

然后这个问题和开关灯的问题的解决办法很类似

然后这两个题目我都没有什么解决办法……

这种矩阵里面计数或者是寻求最少改变数字类型的题目,往往就U懵掉,只是去找规律去寻求自己所谓的正确的解法

会计算,会找规律,会递推,会多加一次然后想到再除以2……总之等等等等方法可能都已经想过,在我的认知中却没有什么思路可以解题。

也不是没有想到过逐一枚举,但是那要怎么枚举呢,要枚举到什么时候呢……想想就否定了。

而本题的正确解法就是枚举,只不过这道题和开关灯的问题一样,不需要你全部枚举,只需要你枚举一下第一行的情况,剩下的全是可以递推出来的

也就是说,对于一个有n列的矩阵来说,全部的情况只有2^n种,当n不是太大的时候,这个枚举量完全可以接受。

希望两道题过后自己可以吸收这种解决问题的方式,“枚举开头,余下递推”的思想

以下将对代码做分析:

#include <cstdio>
#define M 20
int n, min, a[M][M], b[M][M];
int calcu(int x, int y)//将其上左右三面的值加起来(如果存在的话),然后返回;
{
    int upx = x-1, upy = y,lex = x, ley = y-1,rix = x, riy = y+1,sum = 0;
    if(upx>=0) sum += b[upx][upy];
    if(ley>=0) sum += b[lex][ley];
    if(riy<n) sum += b[rix][riy];
    return sum;
}
void solve()
{
    for(int i = 0; i < n-1; i++)
        for(int j = 0; j < n; j++)
            b[i+1][j] = calcu(i,j)&1;//这一句的作用在于,如果是偶数,则结果是0,如果是奇数,结果是1;
    int cnt = 0;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(a[i][j]==1&&b[i][j]==0) return;//这种情况并不满足条件,直接结束进行下一次的枚举即可,不用更新min的值
            else cnt+=(a[i][j]!=b[i][j]);
    if(min>cnt) min = cnt;
}
void dfs(int cur)//利用深度优先遍历枚举第一行
{
    if(cur==n)//美剧完之后开始递推下面每一行的情况
    {
        solve();
        return;
    }
    b[0][cur] = 1;
    dfs(cur+1);
    b[0][cur] = 0;
    dfs(cur+1);
}
int main ()
{
    int cas, t = 0;
    scanf("%d",&cas);
    while(t++<cas)
    {
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                scanf("%d",&a[i][j]);
        min = 999;
        dfs(0);//开始枚举;
        printf("Case %d: ",t);
        if(min==999) printf("-1\n");
        else printf("%d\n",min);
    }
    return 0;
}

思想很重要。认认真真实现自己的思路


你可能感兴趣的:(缺少的思路自己尽量接受并吸收)