andre_joy

导航

poj 1753

地址:http://poj.org/problem?id=1753

题意:黑白棋,翻动一个格子,周围相连的格子都翻转,问最少几次使所有棋子颜色相同。

mark:正解高斯消元,第一次写,写了两天,终于理解并ac了~

代码:

#include <stdio.h>
#include <string.h>

int g[20][20];

int min(int a, int b) {return a < b ? a : b;}

int find(int i)
{
    int j;
    for(j = i; j < 17; j++)
        if(g[j][i]) return j;
    return 0;
}

void swap(int i, int j)
{
    int k;
    for(k = 1; k < 19; k++)
        g[i][k] ^= g[j][k] ^= g[i][k] ^= g[j][k];
}

void init()    //初始化关系矩阵
{
    int i,j,k,x,y,tab[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    memset(g, 0, sizeof(g));
    for(i = 0; i < 4; i++)
        for(j = 1; j < 5; j++)
        {
            g[i*4+j][i*4+j] = 1;
            for(k = 0; k < 4; k++)
            {
                x = i+1+tab[k][0];
                y = j+tab[k][1];
                if(x > 0 && x < 5 && y > 0 && y < 5) g[i*4+j][(x-1)*4+y] = 1;
            }
        }
}

void init2(int b[][20])     //初始化增广矩阵并化简
{
    int i,j,k;
    for(i = 1; i < 17; i++)
    {
        g[i][17] = b[0][i];
        g[i][18] = b[1][i];
    }
/*    for(i = 1; i < 17; i++)
    {
        for(j = 1; j < 19; j++)
            printf("%d", g[i][j]);
        printf("\n");
    }
    printf("\n");*/
    for(i = 1; i < 17; i++)
    {
        j = find(i);
        if(!j) continue;
        if(j != i) swap(i, j);
        for(j = i+1; j < 17; j++)
        {
            if(j != i && g[j][i])
                for(k = 1; k < 19; k++)
                    g[j][k] ^= g[i][k];
        }
    }
/*    for(i = 1; i < 17; i++)
    {
        for(j = 1; j < 19; j++)
            printf("%d", g[i][j]);
        printf("\n");
    }*/
}

void solve()
{
    int i,j,k,f1,f2,cnt1,cnt2,min1,min2;
    int x1[20],x2[20];
    f1 = f2 = 0;
    min1 = min2 = 10000000;
    for(i = 13; i < 17; i++) //打印增广矩阵化简后矩阵,可观察到有四行全为0
    {
        if(f1 && f2) break;
        if(g[i][17]) f1 = 1;
        if(g[i][18]) f2 = 1;
    }
    if(f1 && f2)
    {
        printf("Impossible\n");
        return ;
    }
    for(i = 0; i < 16; i++)
    {
        cnt1 = cnt2 = 0;
        memset(x1, 0, sizeof(x1));
        memset(x2, 0, sizeof(x2));
        for(j = 0; j < 4; j++)
        {
            x1[13+j] = x2[13+j] = (i & (1 << j)) ? 1 : 0;    //这个地方找了好半天,一开始直接是正数或者0了,然后一直wa。。。
            if(x1[13+j]) cnt1++,cnt2++;
        }
        for(j = 12; j > 0; j--)
        {
            for(k = j+1; k < 17; k++)
            {
                if(!f1) x1[j] ^= (x1[k] * g[j][k]);
                if(!f2) x2[j] ^= (x2[k] * g[j][k]);
            }
            if(!f1)
            {
                x1[j] ^= g[j][17];
                if(x1[j]) cnt1++;
            }
            if(!f2)
            {
                x2[j] ^= g[j][18];
                if(x2[j]) cnt2++;
            }
        }
        if(!f1) min1 = min(min1, cnt1);
        if(!f2) min2 = min(min2, cnt2);
    }
    printf("%d\n", min(min1, min2));
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    char a[5][5];
    int b[2][20];
    int i,j,k;
    while(~scanf("%s", a[0]))
    {
        init();
        memset(b, 0, sizeof(b));
        for(i = 1; i < 4; i++) scanf("%s", a[i]);
        for(i = 0, j = 1; i < 4; i++)
            for(k = 0; k < 4; k++)
            {
                b[0][j] = (a[i][k] == 'b');
                b[1][j++] = (a[i][k] == 'w');
            }
        init2(b);
        solve();
    }
    return 0;
}

posted on 2012-08-02 22:43  andre_joy  阅读(128)  评论(0编辑  收藏  举报