7/22学习总结(位运算、递推)

学习总结:

今天是训练的第一天,一切都还有事物刚开始的新鲜感。

在学习的过程中,我发现这本书果然不一般,上面的例子是那种我想破脑袋也可能想不出来的例题,心情沉重,空调也好冷,刚开始注意力还算集中,还带着从外面来时的热气,还是比较凉爽的,学习的效率也还算高,就在距离下课还有1个小时左右就开始起鸡皮疙瘩,也没有带电脑,看着代码自己慢慢捉摸,还写上了好多注释,虽然现在再看就觉得看不懂了!但是当初的良苦用心我还是理解的。

今天一共看了位运算、枚举、模拟、递推,在渴望电脑的时候还看了点递归,题解写的跟深搜一样,仔细想想,深搜不就是递归的思想吗!

今晚打练习赛的时候,做出来了两个题,还有一个题感觉思路超级对的!但是卡在了测试12上,(不知道一共几个测试),好想看看第12个测试的样例是什么呐!!如果最后可以发出来测试样例就好了,就可以知道我这个题目思路到底有什么漏洞了,而不是照搬答案。看了解析,知道错哪了,虽然知道错哪了,但是我还是不会改,看了网上的代码之后,才知道原来可以用并查集和深搜来做,并查集的思想跟我的思路一样,但是当除的操作我都忘了,深搜直接不会来着……

题目滑冰,只有在一条水平线上的两个雪堆才能直接到达,否则不能到达。问要添加几个雪堆才能全部都到达。

题解(呵,答案,上深搜,下并查集):

#include <iostream>
using namespace std;
int n,x[101],y[101],i,ans=-1,ver[101];
void dfs(int a)
{
    ver[a]=1;
    for(int i=1; i<=n; i++)
    if((x[i]==x[a]||y[i]==y[a])&&!ver[i])
        dfs(i);
}
int main()
{
    cin>>n;
    for(i=1; i<=n; i++)
        cin>>x[i]>>y[i];
    for(i=1; i<=n; i++)
    {
        if(!ver[i])
        dfs(i),ans++;
    }
    cout<<ans<<endl;
    return 0;
}



#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n;
int fa[1005];
struct Node{
    int x,y;
};
Node a[1005];
int Find(int x){
    if(fa[x]==x)return x;
    return fa[x]=Find(fa[x]);
}
void unite(int x,int y){
    x=Find(x);
    y=Find(y);
    if(x!=y)fa[x]=y;
}
int main()
{
    while(~scanf("%d",&n)){
        for(int i=0;i<=n;i++)fa[i]=i;
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i].x,&a[i].y);
        for(int i=0;i<n;i++)
           for(int j=0;j<n;j++){
              if(a[j].x==a[i].x||a[j].y==a[i].y){
                  unite(i,j);
              }
           }
        int res=0;
        for(int i=0;i<n;i++){
            if(fa[i]==i)res++;
        }
        printf("%d\n",res-1);
    }
    return 0;
}

还巩固了优先队列的操作,刚开始忘了优先队列什么操作了,(最后还是看的以前的博客=_=):priority_queue<int,vector<int>,greater<int> >y;

这是小的优先的优先队列,因为加上了个greater所以要写全队列里面的东西。

今日份知识点:

1.位运算

位运算最开始学,最后掌握……(现在都没有掌握!),感觉不怎么常用,但是一用就全不会的那种。

(1)与:and、&——每一位同真异假。

(2)或:or、|——每一位,只要有一个是真,就是真,全为假结果才为假

(3)非:not、~

(4)异或:xor——一个真、一个假时为真,其余情况为假

2.二进制最高位为符号位,0表示非负数,1表示负数。

其中,0x7fffffff是整数中的最大值,但是我们在为数组赋值赋无穷大的时候,一般赋值为0x3f3f3f3f(用memset时是使用0x3f)。为什么呢?因为这个数的两倍也不超过0x7fffffff,避免上溢和繁琐的判断,每八位数值相同(不知道有啥用)。

3.右移/左移

移动分为左移右移,又细分为算术左移逻辑左移(右移相同)。

左移:

1.逻辑左移:最高位丢失,最低位补0。符号位不再代表符号,只是代表一个数。

2.算术左移:最高位不变(起到覆盖作用),依次左移,尾补0。约等于n*2。

右移:

1.逻辑右移:最高位补0,符号位仍然不再代表符号,低位丢失。

2.算术右移:符号位也右移,但是复制一个符号位再到最高位。其他的依次右移,尾部丢失。

4.状态压缩

枚举的时候,可以用二进制来代表状态,如是否经过过某个点,经过就让某个二进制如00000000的这个点对应的位置变成1,如0001000000表示已经经过了这个位置。在本书中,就利用了这个方法,把他当成一个二维向量的底数之一,用来表示状态,一个点对应好多个状态,一个状态也能对应很多个点,就起到了遍历许多个点,直到所有0都变成1(所有点都遍历过一遍)为止。

状态压缩常用操作:

操作运算
取出整数n在2进制表示下的第k位(n>>k)&1
取出整数n在二进制下的0~k-1位(后k位)n&((1<<k)-1)
把整数n在二进制表示下的第k位取反n xor (1<<k)
把整数n在二进制表示下的第k位赋值1n|(1<<k)
把整数n在二进制表示下的第k位赋值0n&(~(1<<k))

 5.lowbit运算

取反并加一的操作称作lowbit运算。这种运算的作用是获得最低位为1以及它后面的0组成的十进制数值。n-(n&(-n))还可以删除这些最低位,从而获得在此状态下的最低位1以及后面的0组成的数值。这个操作常用以树状数组。

同时,它配合Hash运算可以找出整数二进制表示下的所有是1的位。

lowbit(n)=n&(~n+1)=n&(-n)。第二种方法更好记,推荐。

2.枚举

一个个列举状态,又称作暴力解题,很少需要算法,一个个看是否符合规则就好。但是仍然需要一些技巧。

本课例题为费解的开关,就是我们平时玩的熄灯的游戏。枚举第一行的每个状态(点击方法高达2^n种,n是边界的宽度),然后改变2~n行(深搜,两种路径->点击这个点和不点这个点,继续在此状态下深搜,注意状态的返回),看最后一行是否全绿,全绿此方法可行,算出点击数目,否则看下一种状态。

点击时,一下子变最多五个最少三个格子,格子的变化通过0->1、1->0之间转换表达(取反)。

3.递推

从一个状态到另一个状态,不同状态下求解表达式相同,从小部分推到总体,例题汉诺塔

n个盘子三座塔,经过找规律,可得知d[n]=2*d[n-1]+1。

同理,四座塔既i个盘子在4塔情况下到另一塔,剩余的n-i个盘子在三塔的情况下(i盘子所在塔最顶是最小的盘子,不能放东西,相当于废塔,这n-i个盘子的摆放适用于三座塔的情况下的递推公式)移到d柱,最后这i个盘子在4塔情况下移到d柱上,综上两次f[i],一次d[n-i].

递推公式:f[n]=min{2*f[i]+d[n-i]}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值