初始i=s

每次:i=(i-1) & s

直到i=0

etc.
11000
10000
01000
00000

10000=10001 & 11000
01000=01111 & 11000
00000=00111 & 11000

etc.
11110
11100
11010
11000
10110
10100
10010
10000
01110
01100
01010
01000
00110
00100
00010
00000

证明:
所有i满足 (s & i)==i,
且所有满足 (s & i)==i 的数都出现过

1.
证明:(s & i)==i
因为“i=(i’-1) & s”,

对于i的第t位i(t):

当s(t)=0时,i(t)=_ & 0 = 0
_ & 0 = 0

当s(t)=1时
1 & i(t) = i(t)

所以(s & i)==i成立

2.
证明:
所有满足 (s & i)==i 的数都出现过

对于s中值为0的位 s(t),因为“i=(i’-1) & s”,所以i(t)永远为0

对于s中值位0的位 s(t),因为“i=(i’-1) & s”,所以i(t)永远不会因为s而影响,所以i(t)的值 为(i’-1)的第t位

即“(s & i)==i”相当于原来s中的‘1’组成的数字从11…1到00…0每次减少1的变化,而原来s中的‘0’永远不变

得证

Usage:
共有n个人,当前有m个人可以工作,每个人可以被选或不被选,求出这m个人的所有选择情况(用二进制表示)

Problem:
hiho1516

bfs+状态压缩:

重要的是弄清每次生成新的状态的方法。。。

 #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> struct node
{
long pos,step,sum;
}q[];
//2^16 * 2(两岸) long n,cond[],g[],num[][];//0为起始岸;1为终止岸;2为船 总数(二进制)
long vis1[],vis2[],vis3;
bool vis[][]; bool judge()
{
long i,j,k;
for (j=;j<;j++)
{
for (i=;i<g[cond[j]];i++)
{
k=num[cond[j]][i];
if (((vis1[k] & cond[j])!=) && ((vis2[k] & cond[j])==))
return false;
} // for (i=0;i<n;i++)
// if (((cond[j]>>i) & i)!=1)
// if ( ((vis1[i] & cond[j])!=0) && ((vis2[i] & cond[j])==0) )
// return false;
}
if ((cond[] & vis3)==)
return false;
return true;
} int main()
{
long m,a,b,c,x,y,head,tail,i,j,k,total,pos,pos_,sum,step,mul[];
scanf("%ld%ld",&n,&m);
mul[]=;
for (i=;i<=n;i++)
mul[i]=mul[i-]<<;
total=(<<n)-;
for (i=;i<=total;i++)
{
g[i]=;
j=i;
k=;
while (j>)
{
if ((j & )==)
{
num[i][g[i]]=k;
g[i]++;
}
k++;
j=j>>;
}
} scanf("%ld%ld%ld",&a,&b,&c);
for (i=;i<n;i++)
{
vis1[i]=;
vis2[i]=;
}
vis3=;
for (i=;i<=a;i++)
{
scanf("%ld%ld",&x,&y);
vis1[x]+=<<y;
}
for (i=;i<=b;i++)
{
scanf("%ld%ld",&x,&y);
vis2[y]+=<<x;
}
for (i=;i<=c;i++)
{
scanf("%ld",&x);
vis3+=<<x;
}
for (i=;i<;i++)
for (j=;j<;j++)
vis[i][j]=true; head=;
tail=;
q[].pos=;
q[].step=;
q[].sum=total;
vis[total][]=false; while (head<tail)
{
head++; //另外的优化:
//如果在左边,则送尽量多的人到右边
//如果在右边,则送尽量少的人到左边 //编写程序的简单性:两岸做法的对称性 (Same),从而合二为一 pos=q[head].pos;
pos_=pos ^ ;
sum=q[head].sum;
step=q[head].step+;
//不必取0,前后必会发生变化
for (i=sum;i>;i=(i-) & sum)
if (g[i]<=m)
{
cond[]=i;
cond[pos]=sum-i;
cond[pos_]=total-cond[pos]; if (vis[cond[pos_]][pos_]==true && judge()==true)
{
// printf("%ld %ld\n",cond[pos_],pos_);
if (pos_== && cond[]==total)
{
printf("%ld\n",step);
return ;
}
tail++;
q[tail].pos=pos_;
q[tail].step=step;
q[tail].sum=cond[pos_];
vis[cond[pos_]][pos_]=false;
}
}
}
printf("-1\n");
return ;
}

/*

位运算的优势:
1.相比正常运算极快的运行速度
2.存储的减少
3.程序编写的简单(和不容易出错)

*/

位运算的一种应用 和 hiho1516过河解题报告的更多相关文章

  1. n&m位运算

    在C/C++语言里,&代表取地址或者“位与”运算 1.取变量的地址:&变量名,这将获得该变量的地址,例:int a = 1, &p = a. 2.进行位与运算,格式是:变量1& ...

  2. C语言位运算+实例讲解(转)

    按位或 按位与 按位异或 按位取反 左移右移 C语言位运算 有6种: &, | , ^(亦或), >(右移). 注意:参与位运算的元素必须是int型或者char型,以补码形式出现. 按位 ...

  3. js中的位运算

    按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...

  4. C#枚举中的位运算权限分配浅谈

    常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第 ...

  5. Java位运算经典实例

    一 源码.反码.补码 正数的源码.反码.补码相同,例如5:            5的源码:101            5的反码:101            5的补码:101 负数的源码.反码.补 ...

  6. EF架构~为分组添加位运算聚合方法

    回到目录 我们知道在Linq里的分组groupby可以对集合中一个或者多个字段进行分组,并对其中一个属性进行聚合,而Linq为我们提供了多种聚合方法,由aver,sum,count等,而在大叔权限体系 ...

  7. leetcode - 位运算题目汇总(下)

    接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...

  8. 深入理解计算机系统(2.2)---布尔代数以及C语言上的位运算

    布尔代数上的位运算 布尔代数是一个数学知识体系,它在0和1的二进制值上演化而来的. 我们不需要去彻底的了解这个知识体系,但是里面定义了几种二进制的运算,却是我们在平时的编程过程当中也会遇到的.这四种运 ...

  9. 关于PHP位运算的简单权限设计

    写在最前面 最近想写一个简单的关于权限处理的东西,之前我也了解过用二进制数的位运算可以出色地完成这个任务.关于二进制数 的位运算,常见的就是“或.与.非”这三种简单运算了,当然,我也查看了下PHP手册 ...

随机推荐

  1. DeepFM算法解析及Python实现

    1. DeepFM算法的提出 由于DeepFM算法有效的结合了因子分解机与神经网络在特征学习中的优点:同时提取到低阶组合特征与高阶组合特征,所以越来越被广泛使用. 在DeepFM中,FM算法负责对一阶 ...

  2. 程序员大佬推荐的java学习路线

    作为我的第一篇博客,我第一个想到的就是在校时就看到的这篇文章.并且在之后的时间里自己都反复观看过,有时候这不单单是一篇学习路线,也是审视自己技术能力的里程碑,和激励自己的鞭挞绳. 先来个书籍清单: & ...

  3. 数位DP模板详解

    // pos = 当前处理的位置(一般从高位到低位) // pre = 上一个位的数字(更高的那一位) // status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回, // 给计 ...

  4. Ps矩形工具的运用

    矩形工具 1.标识位置以及快捷键 位于左侧工具栏中,快键键是u,根据需求选择里面包含的工具 2.使用方法 鼠标左键点击工具,直接在图层使用,点击后拖住不放选择想要的图形后松手即可. 可以根据自身的需求 ...

  5. Jmeter目录文件讲解

    1.bin:核心可执行文件,包含配置 2.windows启动文件:jmeter.bat mac或linux启动文件:jmeter jmeter-server:mac或linux分布式压测启动文件 jm ...

  6. Java设置PPT的扇形图,与内嵌Excel联动

    /** * 设置饼图的主方法 * @param slide 图表 * @param index 图标位置 * @param data 需要设置的数据 * @param titles 关联Excel的标 ...

  7. 怎么用JavaScript写一个区块链?

    几乎所有语言都可以编写区块链开发程序.那么如何用JavaScript写一个区块链?以下我将要用JavaScript来创建1个简单的区块链来演示它们的内部到底是怎样工作的.我将会称作SavjeeCoin ...

  8. 微软职位内部推荐-Sr. SE - Office incubation

    微软近期Open的职位: Senior Software Engineer-Office Incubation Office China team is looking for experienced ...

  9. 10慕课网《进击Node.js基础(一)》初识promise

    首先用最简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</titl ...

  10. 我是一个程序猿 ——《不是书评 :<我是一只IT小小鸟>》有感

    读了刘未鹏先生的文章<不是书评 :<我是一只IT小小鸟>>,产生了诸多共鸣,更明白了不少道理. 首先是一个很平常的现象,进度条效应,在操作移动终端上的软件时,如果没有进度条,人 ...