【笔记+模板】图论 持续更新中

模板参见

http://blog.csdn.net/loi_lxt/article/details/78249982

存图

//vector存图
vector<int> tu[N],cost[N];
void build(int f,int t,int v){
    tu[f].push_back(t);
    cost[f].push_back(v);
    return ;
}
//邻接表存图
struct edge{
    int f,t,v;
}e[M];
int next[M],first[N],tot;
memset(first,-1,sizeof(first));
void build(int f,int t,int v){
    e[++tot]=(edge){f,t,v};
    next[tot]=first[f];
    first[f]=tot;
    return ;
}

二分图判定

搜索,二分图染色

最短路

1.无权图

无权图:权值相等的图
bfs,dis=层数*权值;

2.有权图

Floyd 多源最短路
for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

f[k][i][j]表示只经过1-k,i-j的最短距离;

SPFA(优化的BF)

可以处理负权,不能处理负环;

void spfa(int x){
    dis[x]=0;
    while(!Q.empty()) Q.pop();
    Q.push(x);
    inq[x]=1;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        inq[u]=0;
        for(int i=first[u];i=-1;i=next[i]){
            int v=e[i].t;
            if(dis[v]>dis[u]+e[i].v){
                dis[v]=dis[u]+e[i].v;
                if(!inq[v]) Q.push(v),inq[v]=1;
            }
        }
    }
    return ;
}

玄学优化:
1.改stl里的队列为栈,栈快一丢丢;
2.双端队列优化,对于要放入队列的v,将其的dis与队首的元素s的dis比较,
dis[v]大于dis[s] v放队尾;
dis[v]小于dis[s] v放队首;
stl里的双端队列慢且优化效果宣勋,慎重优化;
3.spfa_cy %%%%cy学长

Dijkstra’s Algorithm

基于贪心思想的最短路算法,不能处理负权;

struct node{
    int x;int dis;
};
bool operator < (node a,node b){
    return a.dis>b.dis;
}
priority_queue<node> Q;

void dij(int x){
    dis[x]=0;
    while(!Q.empty()) Q.pop(); 
    Q.push((node){x,0});
    while(!Q.empty()){
        node u=Q.top();Q.pop();
        if(used[u.x]) continue;
        used[u.x]=1;
        for(int i=0;i<tu[u.x].size();i++){
            int v=tu[u.x][i];
            if(dis[v]>dis[u.x]+cost[u.x][i]){
                dis[v]=dis[u.x]+cost[u.x][i];
                Q.push((node){v,dis[v]});
            }
        }
    }
    return ;
}

dij中,在元素x出堆的瞬间,x的最短路已经确定,所以可以得到终点最短路后直接返回;
dij的贪心证明
从起点到一个点的最短路径一定会经过至少一个“中转点”(把起点也看作一个中转点)
在求某点的最短路之前,它的中转点的最短路一定被确定了
堆中存的是待确定最短路的点即它们的某些状态,
取出堆中dis最小的点x,它的中转点的dis小于x的dis,所以它的中转点一定早于x被拿出堆;
那么x的中转点最短路已确定,x的dis是由确定最短路的点(包括中转点)更新来的,所以x的dis就是x的最短路。
证毕;

最小生成树

1.kruskal算法

主要运用了排序和并查集的思想;
将所有的边排序,按照权值从小到大依次尝试是否加入最小生成树中,
同时用并查集维护节点之间的联通关系
时间复杂度主要在 排序nlogn,因此不适用于稠密图

2.prim

百度百科的prim讲解超级棒

https://baike.baidu.com/item/Prim/10242166?fr=aladdin

算法流程(引自百度百科)
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边< u , v >,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将 < u, v > 边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。

优化
prim算法在选取当前权值最小的边时,朴素算法需要枚举一遍,类似于迪杰斯特拉算法,我们可以用一个堆(优先队列)来将寻找的时间复杂度由O(n)降到O(logn)

3.朴素prim,堆优化prim和kruskal的算法效率实测

http://blog.csdn.net/gykimo/article/details/8538275

差分约束

详见
http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html

差分约束系统就是将一些系数为-1,1的不等式关系,转化为图上最长最短路问题,利用一系列最短路算法(或变形)求解的一类问题

需要注意的是
最小值时,即给定一系列形如

b>=k1
b>=k2
b>=k3
.....

的不等关系时,b的最小值为max{k},所以求的是最长路
将不等关系整理为下式,建图做最长路

d[v]>=d[u]+ < u,v >

求最大值时,

b<=k1
b<=k2
b<=k3
.....

答案是min{k},求最短路

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值