加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 1681 高斯消元

(2010-03-28 21:07:00)
标签:

杂谈

分类: 杂题

    题目描述:一个n*n的网格图,每一格是白色和黄色任意一种颜色,你点击一个格子的时候,这个格子和它上下左右四周的格子都变色(黄->白或者 白->黄),现在给你一个初始的图,问你最少需要点多少次能使这个图的颜色编程全黄的。 n <= 15

    高斯消元(貌似可能有错误的情况,但是能过此题,而且思路很巧妙,不妨总结一下):

    把n*n个格子看成n*n个变量,系数矩阵为A,答案矩阵为B,A * X = B, A[i][j] = 1当且仅当第j个格子变化会影响到第i个格子变化。B[i] = 1表示第i个格子开始时不是黄色(即第i个格子最后的结果是要变化)。

    比如

    3
    yyy
    yyy
    yyy

    系数矩阵为                结果矩阵为

1 1 0 1 0 0 0 0 0             0
1 1 1 0 1 0 0 0 0             0
0 1 1 0 0 1 0 0 0             0
1 0 0 1 1 0 1 0 0             0
0 1 0 1 1 1 0 1 0             0
0 0 1 0 1 1 0 0 1             0
0 0 0 1 0 0 1 1 0             0
0 0 0 0 1 0 1 1 1             0
0 0 0 0 0 1 0 1 1            

    第一行为例:能影响到第一个格子变化的有,第1个,第2个,第4个(2行1列为第四个)。

    结果为0说明能影响到第一个格子变化的总和为2的倍数,即不会变化。

    因此解次方程组,结果为1的表示这个格子需要变化,统计有几个格子需要变化就是答案。

#include<iostream>
#include<cmath>
using namespace std;
#define N 225
#define M 225
typedef int zzy;
zzy fab(zzy x) {return (x > 0 ? x : -x);}
void swap(zzy &x, zzy &y) { zzy temp = x; x = y; y = temp;}
zzy A[N][M 1]; //N 行 M 1列:多出来的一列是答案b列,增广矩阵
int move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int gaos(int r, int c)// c 为系数矩阵实际的列数,不带最后一列的增广部分
{
    int i = 0, j = 0;
    while(i < r && j < c)
    {
        int id = i;
        for(int k = i 1; k < r; k )
            if (fab(A[k][j]) > fab(A[id][j]))
                id = k;
        zzy temp;
        if (A[id][j] != 0)
        {
            temp = A[id][j];
            for(int k = j; k < c 1; k )
                swap(A[id][k], A[i][k]);
            for(int k = i 1; k < r; k )
                if (A[k][j] != 0)
                    for(int l = j; l < c 1; l )
                        A[k][l] = A[k][l] ^ A[i][l];
            i ;
        }
        j ;
    }
    for(int k = i; k < r; k )
        if (A[k][c] != 0)
            return -1; // 无解
    int cnt = A[r - 1][c];
    for(i = r - 2; i >= 0; i--)
    {
        for(j = i 1; j < r; j )
            A[i][c] ^= (A[i][j] && A[j][c]);
        cnt = A[i][c];
    }
    return cnt;//无穷解
}
char x[16][16];
int main()
{
    //freopen("aaa.txt", "w", stdout);
    int t, n;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        memset(A, 0, sizeof(A));
        for(int i = 0; i < n; i )
            scanf("%s", x[i]);
        for(int i = 0; i < n; i )
            for(int j = 0; j < n; j )
            {
                if (x[i][j] != 'y')
                    A[i * n j][n * n] = 1;
                A[i * n j][i * n j] = 1;
                for(int k = 0; k < 4; k )
                {
                    int a = i move[k][0], b = j move[k][1];
                    if (a >= 0 && a < n && b >= 0 && b < n)
                        A[i * n j][a * n b] = 1;
                }
            }
        int ans = gaos(n * n, n * n);
        if (ans == -1)
            printf("inf\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有