ACM近期之学习总结

先说一下这几天的学习情况吧。这几天虽然vjudge上的题目不能提交啦,但是还是要以前没有看过的题补一遍。其中,做了几道dfs和bfs的题目,还看了几道bfs+bit位运算结合,以及Full Tank(最短路径+dp)最短路径变形的问题。我感觉这两个知识点掌握的不是很好,只是略懂皮毛,没有理解的很透彻,能够达到熟练应用到解决问题的地步,所以接下来几天要把这些问题尽可能消化吸收。

 

单源最短路径---Dijkstra算法

一.算法目的

这个算法所求的是单源最短路径,好比说你写好了Dijkstra的函数,那么只要输入点a的编号,就可算出图上每个点到这个点的距离。

时间复杂度是O(n²)

二. 算法详解

给你一个无向图。

5 6(5代表5个点,6代表5个点构成的6个临边)
1 2 5
1 3 8
2 3 1
2 4 3
4 5 7
2 5 2

Dijkstra 算法的步骤如下

1当到一个时间点时,图上部分的点的最短距离已确定,部分点的最短距离未确定。

2、选一个所有未确定点中离源点最近的点,把他认为成最短距离。

3、再把这个点所有出边遍历一边,更新所有的点。

 

注:此处以下地方不明白,以后要继续学习

写此代码的大致思路为:首先用邻接表实现dijkstra,但是这个算法有一个坏处,就是出现负权边,这个算法就炸了,要解决负权边,就要用到SPFA。

由于朴素的Dijkstra时间复杂度是n^2,但是,如果经过堆优化,Dijkstra的时间复杂度能达到nlogn,那么堆优化怎么优化?在这里,我们可以用一个优先队列,每当搜索到一个新点,扔到优先队列里面,这样每次就取队首的绝对是最优值。这样可以省去for循环。(现在不理解,只能硬性记住)

转自https://www.cnblogs.com/jason2003/p/7222182.html

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define in(a) a=read()
#define REP(i,k,n) for(long long i=k;i<=n;i++)
#define MAXN 10010
using namespace std;
typedef pair<long long,long long> P;
inline long long read(){
    long long x=0,t=1,c;
    while(!isdigit(c=getchar())) if(c=='-') t=-1;
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x*t;
}
long long n,m,s;
long long total=0,head[MAXN],nxt[MAXN<<10],to[MAXN<<10],val[MAXN<<10];
long long dis[MAXN],vis[MAXN];
priority_queue <P, vector<P>,greater<P> > Q;//优先队列优化
inline void adl(long long a,long long b,long long c){
    total++;
    to[total]=b;
    val[total]=c;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void Dijkstra(){
    REP(i,1,n)  dis[i]=2147483647;
    dis[s]=0;
    Q.push(P(0,s));
    while(!Q.empty()){
        long long u=Q.top().second;//取出dis最小的点
        Q.pop();//弹出
        if(vis[u])  continue;
        vis[u]=1;
        for(long long e=head[u];e;e=nxt[e])
            if(dis[to[e]]>dis[u]+val[e]){
                dis[to[e]]=dis[u]+val[e];
                Q.push(P(dis[to[e]],to[e]));//插入
            }
    }
    return ;
}
int main(){
    in(n),in(m),in(s);
    long long a,b,c;
    REP(i,1,m)  in(a),in(b),in(c),adl(a,b,c);
    Dijkstra();
    REP(i,1,n)  printf("%lld ",dis[i]);
}
    

 

位运算知识点 (位运算可用于搜索中状态不好表达时的状态压缩)

C++提供了6种位运算符来进行位运算操作:
&      按位与
|      按位或
^      按位异或
~      按位取反
<<     左移(左边消失,右边补0)
>>     右移(右边消失,左边补符号位)
位运算的操作数是整数类型或字符型.

 

按位与运算(&)

两个位同为1,结果才是1,否则为0。(如果是负数参与了运算,则负数以补码形式参与所有位运算)

例如:6的二进制是110,11的二进制是1011,那么6 & 11的结果就是2 

按位与运算(&)的用法:

& 常用于二进制取位操作,例如一个数 & 1的结果就是取二进制的最末位。

 

按位或(|)运算

参与运算的两位只要有1个1则结果为1, 只有两位均为0结果才是0。(  0|0=0    0|1=1    1|1=1  )

2|5 即 00000010 | 0000 0101 = 00000111  因此,3|5的值得7。 

按位或(|)运算用法:

|运算通常用于二进制特定位上的强制置1,例如一个数或 1的结果就是把二进制最末位强行变成1。

 

按位异或^运算

参与运算的两位如果相同则结果为0,参与运算的两位如果不同则结果为1。(  0^0=0  0^1=1  1^1=0   )

 

 

 左移<<运算

 a << b就表示把a转为二进制后左移b位(在后面添b个0)。

例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。

 左移<<运算应用:

可以用<<来定义MAXN等常量。

 

 右移>>运算

a >> b表示二进制右移b位(去掉末b位)

右移(>>)应用举例:

1.x = x >> 1等价于x = x / 2

2.x = x >> n等价于x = x / 2^n

当a是正整数时,a>>b等价于a/(2的b次方)
当a是负整数时,a>>b并不等价与a/(2的b次方),而是等于a/(2的b次方)上取整。
如a=-9
cout<<a/2; //输出-4.
cout<<(a>>1); //输出-5.

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值