poj 2813 画家问题(枚举局部)

程序设计实习枚举作业 poj 2813 画家问题(枚举局部)
总时间限制: 1000ms 内存限制: 65536kB

描述
有一个正方形的墙,由N*N个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。Bob是个画家,想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i, j)个位置的砖时, 位置(i-1, j)、 (i+1, j)、 (i, j-1)、 (i, j+1)上的砖都会改变颜色。请你帮助Bob计算出最少需要涂画多少块砖,才能使所有砖的颜色都变成黄色。
poj 2813 画家问题(枚举局部)_第1张图片

输入
第一行是一个整数n (1≤n ≤15),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。

输出
一行,如果Bob能够将所有的砖都涂成黄色,则输出最少需要涂画的砖数,否则输出“inf”。

样例输入
5
wwwww
wwwww
wwwww
wwwww
wwwww

样例输出
15

来源
poj 1681

直接枚举肯定会超时,注意到按照行的顺序枚举,第一行的操作唯一确定了后面几行的合法操作,所以采用枚举第一行操作的思路。第一次做使用位运算做,效率较高。第二次做到时候为了节省代码量采用了一种虚拟边框的方法,,也没有使用位运算而直接储存,故效率不如第一版。本题也可以用异或方程组,但是实现困难,而且最后对解的自由维度也必须枚举,复杂度上并没有优势,加上代码复杂度较高,而且我高斯消元不熟练所以没有写。

以下为代码

version 1
Accepted 256kB 100ms 1086 B

#define INF 225
#include<stdio.h>

long int row[16]={0},record[15]={0};
int n,minStep=INF,step;

int get(int m,int j)
{
    if (j==-1 || j==n)
        return 0;
    else
        return (m&(1<<j))>>j;
}

void readIn()
{
    char ch;
    int i=0,j=0;
    scanf("%d\n",&n);
    while (i<n)
    {
        scanf("%c",&ch);
        if (ch=='w' || ch=='y')
        {
            row[i]|=((ch=='w')<<j);
            j=((j==n-1)?i++,0:j+1);
        }
    }
}

int main()
{
    readIn();
    for (int m=0;m<(1<<n);m++)
    {
        for (int i=0;i<n;i++)
            record[i]=row[i];
        step=0;
        for (int j=0;j<n;j++)
            step+=get(m,j);
        for (int j=0;j<n;j++)
            row[0]^=(get(m,j-1)^get(m,j)^get(m,j+1))<<j;
        for (int j=0;j<n;j++)
            row[1]^=(get(m,j))<<j;
        for (int i=1;i<n;i++)
        {
            for (int j=0;j<n;j++)
                step+=get(row[i-1],j);
            for (int j=0;j<n;j++)
                row[i]^=(get(row[i-1],j-1)^get(row[i-1],j)^get(row[i-1],j+1))<<j;
            for (int j=0;j<n;j++)
                row[i+1]^=(get(row[i-1],j))<<j;
            row[i-1]=0;
        }
        if (row[n-1]==0 && step<minStep)
            minStep=step;
        for (int i=0;i<n;i++)
            row[i]=record[i];
    }
    if (minStep==INF)
        printf("inf\n");
    else
        printf("%d\n",minStep);
    return 0; 
}

version 2
Accepted 260kB 170ms 1012 B G++


#define MAX_N 15
#define INF 0x7FFFFFFF

#include<stdio.h>

const int dir[5][2]={{0,0},{1,0},{0,1},{-1,0},{0,-1}};

int state[MAX_N+1][MAX_N+1],map[MAX_N+1][MAX_N+1];
int n,min=INF;
char ch;

void print(int i,int j)
{
    for (int d=0;d<=4;d++)
        state[i+dir[d][0]][j+dir[d][1]]^=1;
    return;
}

void deal_row(int k,int total)
{
    if (k==n+1)
    {
        for (int j=1;j<=n;j++)
            if (state[n][j]==0)
                return;
        if (total<min)
            min=total;
        return;
    }
    for (int i=1;i<=n;i++)
        if (state[k-1][i]==0)
        {
            total++;
            print(k,i);
        }
    deal_row(k+1,total);
    return;
}

int main()
{
    scanf("%d\n",&n); 
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++)
        {
            scanf("%c",&ch);
            map[i][j]=(ch=='y');
        }
        scanf("\n");
    }
    for (int state_code=0;state_code!=(1<<n);state_code++)
    {
        for (int i=1;i<=n;i++)
            state[0][i]=(state_code>>(i-1))&1;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                state[i][j]=map[i][j];
        deal_row(1,0);
    }
    if (min==INF)
        printf("inf\n");
    else
        printf("%d\n",min);
    return 0;
}

你可能感兴趣的:(poj 2813 画家问题(枚举局部))