POJ 1222【异或高斯消元|二进制状态枚举】

题目链接:【http://poj.org/problem?id=1222】

题意:Light Out,给出一个5 * 6的0,1矩阵,0表示灯熄灭,反之为灯亮。输出一种方案,使得所有的等都被熄灭。

题解:首先可以用高斯消元来做,对于每个点,我们列出一个方程,左边是某个点和它相邻的点,他们的异或值等于右边的值(灯亮为1 ,灯灭为0),然后求一个异或高斯消元就可以了。可以用bitset优化,或者__int128优化(其实unsigned就可以了)。

  还可以枚举第一行的按开关的状态共有1<<6中状态,从上到下检查,如果某一行的某一个灯是亮的,那只有用按下下一行的这个位置的开关使得这个位置的灯熄灭,最后判断最后一行是否熄灭就可以了。

高斯消元:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 35;
int T;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int a[maxn][maxn], ans[maxn];
int idx(int x, int y)
{
    return (x - 1) * 6 + y;
}
void Guess()
{
    int i, j, k, l;
    for(i = 1, j = 1; i <= 30 && j <= 30; j++)
    {
        for(k = i; k <= 30; k++)
            if(a[k][j]) break;
        if(a[k][j])
        {
            for(l = 1; l <= 31; l++) swap(a[i][l], a[k][l]);
            for(l = 1; l <= 30; l++) //debug从1开始(回代)
            {
                if(l != i && a[l][j])
                    for(k = 1; k <= 31; k++)
                        a[l][k] ^= a[i][k];
            }
            i++;
        }
    }
    for(int j = 1; j < i; j++) ans[j] = a[j][31];
    //自由元不是必须按的,则标记为0
}
int main ()
{
    int ic =0;
    scanf("%d", &T);
    while(T--)
    {
        memset(a, 0, sizeof(a));
        for(int i = 1; i <= 5; i++)
            for(int j = 1; j <= 6; j++)
            {
                scanf("%d", &a[idx(i, j)][31]);
            }
        for(int i = 1; i <= 30; i++)
        {
            a[i][i] = 1;
            int X = (i - 1) / 6 + 1;
            int Y = i - idx(X, 0);
            for(int j = 0; j < 4; j++)
            {
                int x = X + dir[j][1];
                int y = Y + dir[j][0];
                if(x < 1 || y < 1 || x > 5 || y > 6) continue;
                a[i][idx(x, y)] = 1;
            }
        }
        Guess();
        printf("PUZZLE #%d\n",++ic);
        for(int i = 1; i <= 30; i++)
        {
            printf("%d", ans[i]);
            if(!(i % 6)) printf("\n");
            else printf(" ");
        }

    }
    return 0;
}

Bitset:

#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 35;
int T;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
bitset<maxn>a[maxn];
int idx(int x, int y)
{
    return (x - 1) * 6 + y;
}
void Guess()
{
    int i, j, k, l;
    for(i = 1, j = 1; i <= 30 && j <= 30; j++)
    {
        for(k = i; k <= 30; k++)    if(a[k][j]) break;
        if(a[k][j])
        {
            swap(a[i], a[k]);
            for(l = 1; l <= 30; l++) //debug从1开始(回代)
                if(l != i && a[l][j])   a[l] ^= a[i];
            i++;
        }
    }
}
int main ()
{
    int ic = 0;
    scanf("%d", &T);
    while(T--)
    {
        for(int i = 1; i <= 31; i++) a[i].reset();
        for(int i = 1; i <= 5; i++)
            for(int j = 1; j <= 6; j++)
            {
                int t = 0 ;
                scanf("%d", &t);
                if(t)   a[idx(i, j)].set(31);
            }
        for(int i = 1; i <= 30; i++)
        {
            a[i][i] = 1;
            int X = (i - 1) / 6 + 1;
            int Y = i - idx(X, 0);
            for(int j = 0; j < 4; j++)
            {
                int x = X + dir[j][1];
                int y = Y + dir[j][0];
                if(x < 1 || y < 1 || x > 5 || y > 6) continue;
                a[i].set(idx(x, y));
            }
        }
        Guess();
        printf("PUZZLE #%d\n", ++ic);
        for(int i = 1; i <= 30; i++)
        {
            if(a[i][31]) printf("1");
            else printf("0");
            if(!(i % 6)) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

 unsigned:

#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 35;
int T;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
unsigned long long a[maxn];
int idx(int x, int y)
{
    return (x - 1) * 6 + y;
}
void Guess()
{
    int i, j, k, l;
    for(i = 1, j = 1; i <= 30 && j <= 30; j++)
    {
        for(k = i; k <= 30; k++)    if(a[k] & ((unsigned long long)1 << (j - 1))) break;
        if(a[k] & ((unsigned long long)1 << (j - 1)))
        {
            swap(a[i], a[k]);
            for(l = 1; l <= 30; l++)
                if(l != i && a[l] & ((unsigned long long)1 << (j - 1)))   a[l] ^= a[i];
            i++;
        }
    }
}
int main ()
{
    int ic = 0;
    scanf("%d", &T);
    while(T--)
    {
        for(int i = 1; i <= 31; i++) a[i] = 0;
        for(int i = 1; i <= 5; i++)
            for(int j = 1; j <= 6; j++)
            {
                int t = 0 ;
                scanf("%d", &t);
                if(t)   a[idx(i, j)] |= ((unsigned long long)1 << 30);
            }
        for(int i = 1; i <= 30; i++)
        {
            a[i] |= ((unsigned long long)1 << (i - 1));
            int X = (i - 1) / 6 + 1;
            int Y = i - idx(X, 0);
            for(int j = 0; j < 4; j++)
            {
                int x = X + dir[j][1];
                int y = Y + dir[j][0];
                if(x < 1 || y < 1 || x > 5 || y > 6) continue;
                a[i] |= ((unsigned long long)1 << idx(x, y) - 1);
            }
        }
        Guess();
        printf("PUZZLE #%d\n", ++ic);
        for(int i = 1; i <= 30; i++)
        {
            if(a[i] & ((unsigned long long)1 << 30)) printf("1");
            else printf("0");
            if(!(i % 6)) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

  

二进制状态枚举:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 15;
int T;
int a[maxn][maxn], tmp[maxn][maxn], ans[maxn][maxn];
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
void flip(int x, int y)
{
    ans[x][y] = 1;
    tmp[x][y] ^= 1;
    for(int i = 0; i < 4; i++)
    {
        int X = x + dir[i][0];
        int Y = y + dir[i][1];
        if(X < 1 || X > 5 || Y < 1 || Y > 6) continue;
        tmp[X][Y] ^= 1;
    }
}
int main ()
{
    int ic = 0;
    scanf("%d", &T);
    while(T--)
    {
        for(int i = 1; i <= 5; i++)
            for(int j = 1; j <= 6; j++)
                scanf("%d", &a[i][j]);
        for(int k = 0; k <= (1 << 6) - 1; k++)
        {
            for(int i = 1; i <= 5; i++)
                for(int j = 1; j <= 6; j++)
                    tmp[i][j] = a[i][j], ans[i][j] = 0;
            int t = k, pos = 1;
            while(t)
            {
                if(t & 1) flip(1, pos);
                t >>= 1;
                pos++;
            }
            for(int i = 1; i <= 4; i++)
                for(int j = 1; j <= 6; j++)
                    if(tmp[i][j]) flip(i + 1, j);
            int sum = 0;
            for(int i = 1; i <= 6; i++)
                sum += tmp[5][i];
            if(!sum) break;
        }
        printf("PUZZLE #%d\n",++ic);
        for(int i = 1; i <= 5; i++)
        {
            for(int j = 1; j <= 5; j++)
                printf("%d ", ans[i][j]);
            printf("%d\n", ans[i][6]);
        }
    }
    return 0;
}

  

时间: 2024-11-03 13:55:32

POJ 1222【异或高斯消元|二进制状态枚举】的相关文章

POJ 1681 Painter&#39;s Problem 【高斯消元 二进制枚举】

任意门:http://poj.org/problem?id=1681 Painter's Problem Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7667   Accepted: 3624 Description There is a square wall which is made of n*n small square bricks. Some bricks are white while some bric

[ACM] POJ 2947 Widget Factory (高斯消元)

Widget Factory Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 4436   Accepted: 1502 Description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to

poj 1830 开关问题 高斯消元

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

POJ 1166 The Clocks 高斯消元 + exgcd(纯属瞎搞)

根据题意可构造出方程组,方程组的每个方程格式均为:C1*x1 + C2*x2 + ...... + C9*x9 = sum + 4*ki; 高斯消元构造上三角矩阵,以最后一个一行为例: C*x9 = sum + 4*k,exgcd求出符合范围的x9,其他方程在代入已知的变量后格式亦如此. 第一发Gauss,蛮激动的. #include <algorithm> #include <iostream> #include <cstring> #include <cstd

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2

poj 2947 Widget Factory (高斯消元,解模线性方程)

链接:poj 2947 题意:生产一些零件,已知零件种数,记录条数 记录只记录了某次生产从周几开始,周几结束,以及生产了哪些产品. 每件商品生产所需天数为3-9天. 求每样产品需要多少天才能完成. 若无解输出Inconsistent data. 有无穷解输出Multiple solutions. 有唯一解,输出其解 分析:根据题目所给信息,可以列出同余方程组,再根据高斯消元求解, 但还得判断是无解,无穷解,还是唯一解 1.系数矩阵的秩若与增广矩阵的秩不相等,则无解,否则有解 2.若有解,若增广矩

poj 2947 Widget Factory(高斯消元)

description The widget factory produces several different kinds of widgets. Each widget is carefully built by a skilled widgeteer. The time required to build a widget depends on its type: the simple widgets need only 3 days, but the most complex ones

POJ 1222-EXTENDED LIGHTS OUT(高斯消元求解异或方程组)

题目地址:POJ 1222 题意:有一个5*6的矩阵,每个位置都表示按钮和灯,1表示亮,0表示灭.每当按下一个位置的按钮,它和它周围灯的状态全部翻转(题目中给出如何影响),问在这样的一个方阵中按下哪些按钮可以把整个方阵都变成灭的,这时1表示按了,0表示没按. #include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream>

Poj 2947 widget factory (高斯消元解同模方程)

题目连接: http://poj.org/problem?id=2947 题目大意: 有n种类型的零件,m个工人,每个零件的加工时间是[3,9],每个工人在一个特定的时间段内可以生产k个零件(可以相同种类,也可以不同种类),问每种零件生产一个出来需要的时间? 解题思路: 给出的时间段是从周几到周几,并没有给出具体的时间段,因此在计算过程中要进行取模,还有就是对每个零件要在题目要求的范围内进行枚举. ps:如果求出来的增广矩阵是n*n的,但是某个零件在[3,9]之间没有合理的解,也是无解的. 1