一、沃尔什变换公式
沃尔什变换(Walsh Transform),又称Walsh-Hadamard变换,它是一种不带权的正交变换,是傅里叶变换的一种实现方式。
其变换公式如下:
W(u,v) = (-1)^{f(u,v)} \prod_{i=0}^{n-1}w_i(u_i,v_i)
其中:
- u,v为整数,0≤u,v≤n-1
- f(u,v)为u、v的二进制位按位异或的结果
- w_i是Walsh函数,计算方式为:
w_0(x,y) = 1, x,y∈{0,1}
w_i(x,y) = w_{i-1}(x,y)w_{i-1}(x,y⊕2^{i-1}), i≥1
其中 ⊕ 表示按位异或操作。
二、沃尔什变换怎么求
在计算机中,沃尔什变换可以用递归方式实现。
以计算2次沃尔什变换为例:
//计算变换矩阵
int w[4][4];
int WalshMatrix(int x, int y, int n)
{
if (n == 1)
{
w[x][y] = 1;
return 1;
}
int t = n / 2;
WalshMatrix(x, y, t);
WalshMatrix(x + t, y, t);
WalshMatrix(x, y + t, t);
WalshMatrix(x + t, y + t, t);
//递归计算变换
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
int a = w[x + i][y + j];
int b = w[x + i][y + j + t];
int c = w[x + i + t][y + j];
int d = w[x + i + t][y + j + t];
w[x + i][y + j] = a + b + c - d;
w[x + i][y + j + t] = a - b + c + d;
w[x + i + t][y + j] = a + b - c - d;
w[x + i + t][y + j + t] = a - b - c + d;
}
}
}
//调用接口
WalshMatrix(0, 0, 4);
其中,变换矩阵存放在w数组中。
三、沃尔什变换矩阵
沃尔什变换矩阵是一个n×n的矩阵。在上一节中,我们已经介绍了如何计算沃尔什变换矩阵。
例如,当n=4时,沃尔什变换矩阵如下:
1 1 1 1
1 -1 1 -1
1 1 -1 -1
1 -1 -1 1
一个大小为n的Walsh矩阵可以通过将一个大小为2的Walsh矩阵的每个元素除以2,然后将四个2x2矩阵插入到新矩阵的相应位置来生成。当n是2的幂时,可以通过运行时间为O(n log n)的递归算法来计算Walsh矩阵。
四、沃尔什变换可分离
沃尔什变换具有可分离性,即一个n维向量的Walsh变换可以被分解成一维向量的Walsh变换的张量积。
例如,假设我们有一个4×4的Walsh矩阵A,行向量V和列向量U,其中V和U的元素都是±1。因此,如果Y是向量V与U的张量积,那么Y的Walsh变换是矩阵乘积A * V * U'。
五、沃尔什变换核
沃尔什变换核是一个n×n的01矩阵。当n为奇数时,沃尔什变换核的第一行和第一列全为1,其他位置值为0和1交替。当n为偶数时,沃尔什变换核可以通过将大小为n/2的沃尔什变换核缩放2倍并插入到大小为n的核的对应位置来构造。
例如,当n=4时,沃尔什变换矩阵如下:
1 1 1 1
1 -1 1 -1
1 1 -1 -1
1 -1 -1 1
对应的核为:
1 1 0 0
1 1 0 0
0 0 1 1
0 0 1 1
六、沃尔什变换核矩阵怎么算
可以通过下面的递归算法计算沃尔什变换核矩阵:
void WalshCore(int core[][N], int n)
{
if (n == 1)
{
core[0][0] = 1;
return;
}
int t = n / 2;
WalshCore(core, t);
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
core[i][j + t] = core[i + t][j] = core[i + t][j + t] = -core[i][j];
}
}
}
其中,核矩阵存放在core数组中。
七、沃尔什变换系数
沃尔什变换系数是一个大小为n的向量,其中第i个分量为沃尔什函数wi的第i个输入和第n个输入的差的倒数。
例如,当n=4时,沃尔什变换系数是:
1 1/3 1/3 1/3
八、沃尔什变换核矩阵怎么算
可以通过下面的递归算法计算沃尔什变换的系数:
void WalshCoeff(double coeff[], int n)
{
if (n == 1)
{
coeff[0] = 1;
return;
}
int t = n / 2;
WalshCoeff(coeff, t);
for (int i = 0; i < t; i++)
{
coeff[i + t] = coeff[i] / -2;
}
}
其中,系数存放在coeff数组中。
九、沃尔什变换计算题
下面是一个沃尔什变换的计算题:
设f(x)为长度为2^n的01数列,定义g(x)为:g(x) = Sum(f(y) * (-1)^(x⊕y),y∈[0,2^n-1])。请计算g的沃尔什变换。
通过分析题目中的g函数,可以发现它是f函数的沃尔什变换的直接表达式。因此,问题可以转化为计算f的沃尔什变换,然后用系数对其进行加权求和得到g的沃尔什变换。
沃尔什变换的计算方法已经在前面的章节中介绍了,下面给出计算g的代码示例:
const int N = 1 << 22;
int n;
int a[N],b[N];
double c[N];
void Solve(int l, int r) //计算f的沃尔什变换
{
if (l == r) {c[l] = a[l]; return;}
int mid = l + r >> 1;
Solve(l, mid), Solve(mid + 1, r);
memcpy(b, a + l, (r - l + 1) * sizeof(int));
int p = mid - l + 1;
for (int i = 0; i < p; i++)
for (int j = 0; j < (1 << ((int)(log2(r - l + 1) - .5) + 1)); j += 2 * p)
{
int x = b[i + j], y = b[i + j + p];
b[i + j] = x + y, b[i + j + p] = x - y;
}
memcpy(c + l, b, (r - l + 1) * sizeof(double));
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < (1 << n); ++i)
scanf("%d", &a[i]);
Solve(0, (1 << n) - 1);
WalshCoeff(c, (1 << n)); //计算Walsh变换系数
for (int i = 0; i < (1 << n); i++)
printf("%lf\n", c[i]);
return 0;
}
十、沃尔什变换例题
下面是一些沃尔什变换的例题:
例题1:POJ 2752 Shuffle'm Up
题目描述:
给你一个长度为2^n的数列a,这个数列的前一半是a[0], ...,a[2^(n-1)-1],后一半是a[2^(n-1)], ..., a[2^n-1]。并且,对于i∈[0,2^(n-1)-1],有f(i)=a[2i]和f(i+2^(n-1))=a[2i+1];对于i∈[2^(n-1),2^n-1],有f(i)=a[(i-2^n/2)*2+1]和f(i-2^(n-1))=a[(i-2^n/2)*2]。问最后的数列是什么。
输入格式:
第一行一个整数n。接下来的一行包含2^n个整数,表示数列a。
输出格式:
输出一个字符串,表示最后的数列。
解题思路:
参考洗牌算法的思路,将序列分成两部分,然后递归地执行沃尔什变换和乘法运算,最后得到新的序列。
代码如下:
int n;
int a[MAXN];
void shuffle(int l, int r)
{
if (r - l == 1)
return;
int mid = (l + r + 1) >> 1;
for (int i = 0; i <= mid - l - 1; i++)
{
swap(a[l + i], a[mid + i]);
}
shuffle(l, mid);
shuffle(mid, r);
for (int i = l; i < r; i += 2)
{
int x = a[i], y = a[i + 1];
a[i] = (x + y) / 2, a[i + 1] = (x - y) / 2;
}
}
int main()
{
scanf("%d", &n);
int len = (1 << n);
for (int i = 0; i < len; i++)
scanf("%d", &a[i]);
shuffle(0, len);
for (int i = 0; i < len; i++)
putchar(a[i] + 'A