算法学习笔记(1):位运算

快速幂

模板题:a^b

#include <iostream>
using namespace std;
int main()
{
    int a, b, p;
    cin >> a >> b >> p;
    int res = 1 % p;  //模p是防止当p == 1 && b == 0时输出1, 正确答案应为0
    while(b){
        if(b&1) res = res * 1ll * a % p;  //1ll可强制转化为long long类型
        a = a * 1ll * a % p;
        b >>= 1;
    }
    cout << res << endl;
    return 0;
}
/*
该问题求a^b mod p
数据范围: 0≤a,b≤10^9, 1≤p≤10^9
时间复杂度: O(log b)
res用来表示乘积;
快速幂:
    3^7 = 3^1 + 3^2 + 3^4;
    b每次右移1位, 为1时, res乘a
*/

模板题:64位整数乘法

#include <iostream>
using namespace std;
typedef unsigned long long ULL;
int main()
{
    ULL a, b, p;
    cin >> a >> b >> p;
    ULL res = 0;
    while(b){
        if(b&1) res = (res + a) % p;
        a = 2 * a % p;
        b >>= 1;
    }
    cout << res << endl;
    return 0;
}
/*
10^18大概等于2^64, 因此要用unsigned long long
相当于b个a相加
a * b = a + a + a + a + a + a + ...
a * 1 = a
a * 2 = 2a
a * 4 = 4a
...
a *(2^k) =(2^k)a
*/

例题1:最短Hamilton路径(又名:旅行商问题)
位运算的精髓:按位枚举,可将O(n)转化为O(log n)

/*
Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰好一次

假设有4个点:0, 1, 2, 3
0->1->2->3  18
0->2->1->3  20
由此可知, 一个Hamilton路径与中间点无关, 且最短Hamilton路径可以由以下两点表示状态:
1.哪些点被用过(可以用二进制数表示, 1表示用过, 0表示没用过)
2.目前停在哪个点上

f[state][j] = f[state_k][k] + weight[k][j](由k转移到j), state_k表示state去掉j之后的集合, 且state_k要包含k

如果用到了点0 1 4, 则state = 10011
*/

#include <iostream>
#include <cstring>
using namespace std;
const int N = 20, M = 1 << 20;
int n, weight[N][N];
int f[M][N];

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < n; j ++ )
            cin >> weight[i][j];
            
    memset(f, 0x3f, sizeof f);  //因为要求最小值, 所以将f设置最大
    f[1][0] = 0;
    for(int i = 0; i < 1 << n; i ++ )
        for(int j = 0; j < n; j ++ )
            if(i >> j & 1)
                for(int k = 0; k < n; k ++ )
                    if(i - (1 << j) >> k & 1)
                        f[i][j] = min(f[i][j], f[i - (1 << j)][k] + weight[k][j]);
    cout << f[(1 << n) - 1][n - 1] << endl;
    return 0;
}

例题2:起床困难综合症

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值