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

POJ PKU 1830 高斯消元

(2010-03-28 19:36:00)
标签:

杂谈

分类: 杂题

    题目描述:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

    下面是1830怎么和高斯消元联系起来:(转自他人blog,灰常经典)

   对于每个灯有动它和不动它2种状态,用1,0表示,那么可以构造列向量X=[x1,x2....xn],Xi =0 或者1. 系数矩阵B[b1,b2...bn],变换矩阵A[n][n]; 假设 A*X = B,那么bi 等于 A的第i行元素和X对应相乘,那么我们可以这样来设置A[i][j]: 如果第j个灯操作会影响i,那么A[i][j]=1.

如果i的初始化状态和目标状态不同,那么b[i]=1. 因为b[i] 等于 A的第i行元素和X对应相乘。那么也就是说第i个灯最后的状态是不是会变是由X决定的,因为b[i] = sum(a[i][j] * X[j]),这里的求和视为模2运算也就是^,所以第i个灯最后的状态和初始比是不是变了是由每一个和i有关的灯决定的,这也就是为什么j会影响i设A[i][j] = 1的原因。也就是为什么要设b[i]是初始状态和最终状态的异或。。。。。。于是结果就变成了求方程A*X=B有多少个解。

    有了上面的思路代码就很简单了。

#include<iostream>
using namespace std;
#define N 29
#define M 29
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 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; // 无解
    return 1 << (r - i);//无穷解
}
int a[30], b[30];
int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        memset(A, 0, sizeof(A));
        for(int i = 0; i < n; i )
            scanf("%d", &a[i]);
        for(int i = 0; i < n; i )
        {
            scanf("%d", &b[i]);
            if (b[i] != a[i])
                A[i][n] = 1;
            A[i][i] = 1;
        }
        int aa, bb;
        while(scanf("%d%d", &aa, &bb) && aa && bb)
            A[bb - 1][aa - 1] = 1;
        int ans = gaos(n, n);
        if (ans == -1)
            printf("Oh,it's impossible~!!\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}

 

 

0

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

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

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

新浪公司 版权所有