MT神牛的ppt很酷
QW又无节操的蒯了道经典高斯消元的题(Orz)
于是准备给自己普及普及这方面知识
只要以后有这方面题就会写了贴上来
我认为比较重要或是难理解的东西有以下几个
1.关键元概念, 关键元决定了能够去XOR哪个方程
2.自由元与解的数目的关系,若少一个自由元,则解的数目减半(乘法原理)
3.压位存方程(有几种都很优美的实现方式, 方程右边的值为 原始状态 XOR 目标状态)
4.消元
5.回代求解
离线算法 时间复杂度(N2M)
1. poj 1830 开关问题
http://poj.org/problem?id=1830
题意:
给出开关的初始状态与末状态
给出开关之间有相互影响的二元组
求有多少种可以从初始状态转到末状态的方法
用离线算法水过,且此题没有回代求解的需求
code
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int maxn = 29 + 5;
int K, n;
int a[maxn], b[maxn];
void Swap(int &a, int &b) { int T = a; a = b; b = T; }
int main()
{
freopen("poj1830.in", "r", stdin);
freopen("poj1830.out", "w", stdout);
for (scanf("%d", &K); K; --K)
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1, j; i <= n; ++i)
scanf("%d", &j), a[i] = a[i] ^ j;//右数第一位存的是方程右边
for (int i = 1; i <= n; a[i] |= (1 << i), ++i);
//在方程中与自己建立关系
for (int u, v; scanf("%d%d", &u, &v) && u + v != 0; a[v] |= (1 << u));
//即v的变换与u有关
int k = 1, tot = 0;
for (int i = 1; i <= n; ++i)
{
for (int j = k; j <= n; ++j)
if (a[j] >> i & 1) { Swap(a[j], a[k]); break; }
if (!(a[k] >> i & 1)) ++tot;//没有以第i个元为关键元则多一自由元
else
{
for (int j = k + 1; j <= n; ++j)
if (a[j] >> i & 1) a[j] ^= a[k];
++k;
}
}
for (int i = k; i <= n; ++i)//判方程有无解的情况
if (a[i] & 1) { tot = -1; break; }
if (tot == -1) puts("Oh,it's impossible~!!");
else printf("%d\n", 1 << tot);
}
return 0;
}