位运算的一种应用 和 hiho1516过河解题报告

 

初始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+状态压缩:

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

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 
  5 struct node
  6 {
  7     long pos,step,sum;
  8 }q[131073];
  9 //2^16 * 2(两岸)
 10 
 11 long n,cond[3],g[17],num[65537][17];//0为起始岸;1为终止岸;2为船 总数(二进制)
 12 long vis1[17],vis2[17],vis3;
 13 bool vis[65537][2];
 14 
 15 bool judge()
 16 {
 17     long i,j,k;
 18     for (j=0;j<3;j++)
 19     {
 20         for (i=0;i<g[cond[j]];i++)
 21         {
 22             k=num[cond[j]][i];
 23             if (((vis1[k] & cond[j])!=0) && ((vis2[k] & cond[j])==0))
 24                 return false;
 25         }
 26 
 27 //        for (i=0;i<n;i++)
 28 //            if (((cond[j]>>i) & i)!=1)
 29 //                if ( ((vis1[i] & cond[j])!=0)  && ((vis2[i] & cond[j])==0) )
 30 //                    return false;
 31     }
 32     if ((cond[2] & vis3)==0)
 33         return false;
 34     return true;
 35 }
 36 
 37 int main()
 38 {
 39     long m,a,b,c,x,y,head,tail,i,j,k,total,pos,pos_,sum,step,mul[17];
 40     scanf("%ld%ld",&n,&m);
 41     mul[0]=1;
 42     for (i=1;i<=n;i++)
 43         mul[i]=mul[i-1]<<1;
 44     total=(1<<n)-1;
 45     for (i=0;i<=total;i++)
 46     {
 47         g[i]=0;
 48         j=i;
 49         k=0;
 50         while (j>0)
 51         {
 52             if ((j & 1)==1)
 53             {
 54                 num[i][g[i]]=k;
 55                 g[i]++;
 56             }
 57             k++;
 58             j=j>>1;
 59         }
 60     }
 61 
 62     scanf("%ld%ld%ld",&a,&b,&c);
 63     for (i=0;i<n;i++)
 64     {
 65         vis1[i]=0;
 66         vis2[i]=0;
 67     }
 68     vis3=0;
 69     for (i=1;i<=a;i++)
 70     {
 71         scanf("%ld%ld",&x,&y);
 72         vis1[x]+=1<<y;
 73     }
 74     for (i=1;i<=b;i++)
 75     {
 76         scanf("%ld%ld",&x,&y);
 77         vis2[y]+=1<<x;
 78     }
 79     for (i=1;i<=c;i++)
 80     {
 81         scanf("%ld",&x);
 82         vis3+=1<<x;
 83     }
 84     for (i=0;i<65536;i++)
 85         for (j=0;j<2;j++)
 86             vis[i][j]=true;
 87 
 88     head=0;
 89     tail=1;
 90     q[1].pos=0;
 91     q[1].step=0;
 92     q[1].sum=total;
 93     vis[total][0]=false;
 94 
 95     while (head<tail)
 96     {
 97         head++;
 98 
 99         //另外的优化:
100         //如果在左边,则送尽量多的人到右边
101         //如果在右边,则送尽量少的人到左边
102 
103         //编写程序的简单性:两岸做法的对称性 (Same),从而合二为一
104 
105         pos=q[head].pos;
106         pos_=pos ^ 1;
107         sum=q[head].sum;
108         step=q[head].step+1;
109         //不必取0,前后必会发生变化
110         for (i=sum;i>0;i=(i-1) & sum)
111             if (g[i]<=m)
112              {
113                  cond[2]=i;
114                  cond[pos]=sum-i;
115                  cond[pos_]=total-cond[pos];
116 
117                  if (vis[cond[pos_]][pos_]==true && judge()==true)
118                  {
119 //                     printf("%ld %ld\n",cond[pos_],pos_);
120                      if (pos_==1 && cond[1]==total)
121                      {
122                          printf("%ld\n",step);
123                          return 0;
124                     }
125                     tail++;
126                     q[tail].pos=pos_;
127                     q[tail].step=step;
128                     q[tail].sum=cond[pos_];
129                     vis[cond[pos_]][pos_]=false;
130                 }
131             }
132     }
133     printf("-1\n");
134     return 0;
135 }

 

/*

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

*/

 

转载于:https://www.cnblogs.com/cmyg/p/7230998.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值