算法竞赛进阶指南总结(一)

一、位运算

二、递推与递归

位运算:二进制做基础,位运算给了我们一个操作简单的计算机。

位运算基础:

&:按位与,如果两个相应的二进制都为1,则该位值为1,否则为0.

|:按位或,两个相应的二进制位中只要有一个为1,则该位的值为1;

^:按位异或,若参加运算的两个数的值相同,则该值为1,否则为0;

~:取反,一元运算符,用来对二进制数按位取反,1-0,0-1;

<<:左移,用来将一个数的个二进制位全部左移N位,右边补0;

>>:右移,用来将一个数的个二进制位全部右移N位,移到右端的低位被舍弃,对于无符号数,高位补0.

原码、补码、反码:

真值:第一位表示符号位:最高位1表示负值,0表示正值,

原码:符号位加上真实值的绝对值,第一位表示符号,其余位表示值

例如:8位的二进制数

[+1]原码;0000 0001
[-1]原码:1000 0001

所以,8位的二进制数的范围为【1111 1111,0111 1111】[-127.127];

反码:正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余位取反;

例如:

[+1]=[0000 0001]原=[0000 0001]反
[-1]=[1000 0001]原=[1111 1110]反

对于负数,通常也需要转换成原码进行计算;

补码:正数的补码是其本身,负数的补码是在原码的基础上,符号位不变,其余各位取反,最后+1,(反码的基础上+1);

例如:

[+1]=[0000 0001]原=[0000 0001]反=[0000 0001]补
[-1]=[1000 0001]原=[1111 1110]反=[1111 1111]补

二进制状态压缩:将一个长度为m的bool数组,用一个m位的二进制整数表示并储存的方法;

算法竞赛进阶指南总结(一)_第1张图片

例题: 链接:91. 最短Hamilton路径 - AcWing题库

 算法竞赛进阶指南总结(一)_第2张图片

#include
using namespace std;
const int N = 20,M = 1 << N;
//解释一下1 << N:因为i是二进制数,表示从0到当前点的状态,所以每个点都有两个状态0和1,所以是2的N次方
int n;
int w[N][N]; //每条边的权重
int f[M][N]; //表示从0到j,走过的点是i的所有路径
int main()
{
    scanf("%d",&n);
    for(int i = 0;i < n;i ++)
    {
        for(int j = 0;j < n;j ++)
        {
            scanf("%d",&w[i][j]);
        }
    }
    memset(f,0x3f,sizeof f);
    f[1][0] = 0; //0为起点,所以为0
    for(int i = 0;i < 1 << n;i ++)
    { //i表示的所有的状态
        for(int j = 0;j < n;j ++)
        { //j表示走到的哪一点
            if(i >> j & 1){ //如果i的j为1,说明到达过这个点
                for(int k = 0;k < n;k ++)
                { //k表示走到j这个点之前,以k为终点的最短距离
                    if((i - (1 << j)) >> k & 1)
                    { //i除去j这个点后包含k这个点
                        f[i][j] = min(f[i][j],f[i - (1 << j)][k] + w[k][j]); //状态转移,前面图1有详细讲解哦~
                    }
                }
            }
        }
    }
    printf("%d\n",f[(1 << n) - 1][n - 1]); //输出答案
    //(1 << n) - 1表示:有n个1,也就是所有的点都走完了
    //n - 1表示:终点
    //合起来就是所有的点都走完的方案,最后落脚在n - 1这个点
    return 0;
}

成对变换:

对一个非负整数n

n为偶数时,n xor 1=n-1;

n为奇数时,n xor 1=n+1;

lowbit(x)是x的二进制表达式中最低位的1所对应的值。(这利用到了位运算的与运算)

int lowbit(int x)
{
   return x&-x;
}

现在我们来证明一下 lowbit ( n ) 运算是怎么进行运算的:

我们假设 n > 0 ,设 n 的二进制表示中,第 k 位为 1 ,第 0 至第 k-1 位都为 0 ,现在我们对 n 的二进制进行取反操作,可以得到,~n 的二进制表示中,第 k 位为 0 ,第 0 至第 k-1 位都为 1,然后我们再将 ~n 进行加 1 操作,可以得到一个结果,就是 ~n+1 的第 k+1 位至其最高位都为 n 的二进制表示中相反的数字,然后我们再将 ~n+1 与 n进行与运算,就可以得到我们想要的结果了。又因为 ~n=-1-n ,所以 -n = ~n+1,有:

lowbit( x ) = n & ( ~n + 1 ) = n & ( -n )
上面写的很抽象,我们假设 n = 8 ,8 的二进制为 : 0 0 0 0 1 0 0 0   ,对 8 取反的二进制为 :1 1 1 1 0 1 1 1   ,再对 取反8加一的二进制为 :1 1 1 1 1 0 0 0,  进行与操作之后 : 0 0 0 0 1 0 0 0 

就得到了我们的 lowbit ( 8 ) = 8
 

你可能感兴趣的:(c++)