位运算:(二进制)
- ’&’符号,x&y,会将两个十进制数在二进制下进行与运算(都1为1,其余为0) 然后返回其十进制下的值。例如3(11)&2(10)=2(10)。
- ’|’符号,x|y,会将两个十进制数在二进制下进行或运算(都0为0,其余为1) 然后返回其十进制下的值。例如3(11)|2(10)=3(11)。
- ’^’符号,x^y,会将两个十进制数在二进制下进行异或运算(不同为1,其余 为0)然后返回其十进制下的值。例如3(11)^2(10)=1(01)。
- ’~’符号,~x,按位取反。例如~101=010。
- ’<<’符号,左移操作,x<<2,将x在二进制下的每一位向左移动两位,最右边用0填充,x<<2相当于让x乘以4。 ’>>’符号,是右移操作,x>>1相当于给x/2,去掉x二进制下的最右一位
1.判断一个数字x二进制下第i位是不是等于1。(最低第1位)
方法:if(((1<<(i−1))&x)>0) 将1左移i-1位,相当于制造了一个只有第i位 上是1,其他位上都是0的二进制数。然后与x做与运算,如果结果>0, 说明x第i位上是1,反之则是0。
2.将一个数字x二进制下第i位更改成1。
方法:x=x|(1<<(i−1)) 证明方法与1类似。
3.将一个数字x二进制下第i位更改成0。
方法:x=x&~(1<<(i−1))
4.把一个数字二进制下最靠右的第一个1去掉。
方法:x=x&(x−1)
压状dp:
把情况 用 二进制 表示 具体的二进制数中 1 代表 有 0 则是没有 一个二进制数就可以表示一种 情况。 很多个二进制数就可以把情况表示完。
特别注意: 0 的情况也要考虑。
在利用背包的思想,对这些情况进行叭叭。
试题 历届真题 糖果【第十届】【省赛】【A组】 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1 ∼ M。 小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。 幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。 给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖 果。 输入格式 第一行包含三个整数 N、M 和 K。 接下来 N 行每行 K 这整数 T₁, T₂, · · · , TK,代表一包糖果的口味。 输出格式 一个整数表示答案。如果小明无法品尝所有口味,输出 −1。 样例输入 6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2 样例输出 2 评测用例规模与约定 对于 30% 的评测用例,1 ≤ N ≤ 20 。 对于所有评测样例,1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M。
#include <bits/stdc++.h> using namespace std; #define ri register int #define N 10005 template <class G>void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } const int M = 1<<20+2; int dp[M]; int n,m,K; int candy[105]; int main(){ read(n);read(m);read(K); for(ri i=1;i<=n;i++) { for(ri j=1;j<=K;j++) { int a; read(a); candy[i]|=1<<(a-1); } dp[candy[i]]=1; } for(ri i=1;i<=n;i++) { for(ri j=1;j<(1<<m);j++) { if(!dp[j]) continue; /// 就是装满问题 if(dp[j|candy[i]]==0||dp[j|candy[i]]>dp[j]+1) dp[j|candy[i]]=dp[j]+1; } } if(dp[(1<<m)-1]) printf("%d",dp[(1<<m)-1]); else cout<<-1; return 0; }
知识点 : 判断 一个二进制的数 的 1之间是否 有 0隔开 直接 a<<1 &a 看存在是否
判断 2 个二进制数的1 是否 错位 不仅要 a<<1 &b && a>>1&b 关键
注意0的初始情况;
注意 是 围着的那 8 个数
试题 算法提高 鹅卵石 资源限制 时间限制:1.0s 内存限制:256.0MB 题意: 给定一个N*N的方格,让你在里面取出一些数使其和最大,要求每一个数不能与其相邻的8个数同时取出。输出最大和即可。 输入格式 一个N*N 矩阵 输出格式 最大和 样例: 71 24 95 56 54 85 50 74 94 28 92 96 23 71 10 23 61 31 30 46 64 33 32 95 89 输出格式 572
#include <bits/stdc++.h> using namespace std; #define ri register int const int M = 1<<15; int n; vector <int>q; void init() { for(ri i=0;i<(1<<n);i++) { if((i<<1)&i) continue; q.push_back(i); } } int p[21][21]; long long ar[16][M]; void ck(int a,int b) { for(ri i=1;i<=n;i++) { if(b&(1<<(i-1))) { ar[a][b]+=p[a][i]; } } } long long f[16][M]; int qu[M]; int main(){ int cent=0; int aa; while(~scanf("%d",&aa)) { qu[++cent]=aa; } n=sqrt(cent); cent=0; for(ri i=1;i<=n;i++) { for(ri j=1;j<=n;j++) { p[i][j]=qu[++cent]; } } init(); for(ri i=1;i<=n;i++) { for(ri j=0;j<q.size();j++) { int a=q[j]; ck(i,a); } } long long ans=0; for(ri i=0;i<q.size();i++) { int a=q[i]; f[1][a]=ar[1][a]; } for(ri i=2;i<=n;i++) { for(ri j=0;j<q.size();j++) { int a=q[j]; for(ri k=0;k<q.size();k++) { int b=q[k]; if(((b<<1)&a)) continue; if((b>>1)&a) continue; if(b&a) continue; f[i][a]=max(f[i][a],f[i-1][b]+ar[i][a]); } } } for(ri i=0;i<q.size();i++) { int b=q[i]; ans=max(ans,f[n][b]); } printf("%lld",ans); return 0; }
小知识点: 看看如何输入的; 查看时候 正确 就 先回车 在 ctrl + z 回车