zoukankan      html  css  js  c++  java
  • 简谈图论重要性&&图论总结

    从外地学习回来,我对图论才有认识(以前就没接触过,非常尴尬),说实话,学好图论的重要性,就像学数学时在进行解析几何时,图极有可能是打开答案的最后秘钥,也就是数形结合,而懂的人永远明白,用图解决绝对比用解析简单(一般情况)。而图论对于oi选手说,就是一大杀器,有可能利己,也可能抱憾终身。所以说图论的重要性就很显然了。

    大家在进入图论的时候,应该先掌握链式前向星建图,当然也可以叫邻接表,先附上我喜欢的模板

    struct node{
        int next,to,w;
    }edge[maxn<<4];
    
    int head[maxn],cent;
    
    void add(int u,int v,int w){
        edge[++cent]=(node){head[u],v,w}; head[u]=cent;
    }

      

      ——所谓模板,也就是自己喜欢的颜色涂上而已。

      当然还有一些其他知识,比如说vector建图,这种建图的方式优点是难度小,而且还可以排序,这个在NOIP2018的D2T1上有极大优势。

    scan(a),scan(b);
    vec[a].push_back(b);
    vec[b].push_back(a);

      然后只要简单地定义排序一下,即可用食。

      还有树形dp,这在树形图中将是一大助力,这里是dp求直径。

    void dp(int s,int fa){
        for(int i=head[s];i;i=edge[i].next){
            int y=edge[i].to;
            if(vi[y]) continue;
            if(y==fa) continue;
            dp(y,s);
            an=max(anx,root[x]+root[y]+edge[i].w);
            root[s]=max(root[s],root[y]+edge[i].w);
        }
    }

      在入门之后,请仔细思考与总结

      总结方法:

      1. 反向建边 例题

      2. 路径记数,加法原理,并加上限制条件 例题

      3. 巧妙运用二分图的检验 例题

      4. 学习二分图的技巧,学会在只有两种条件有关系时,转化成二分图 例题

      5. 深刻理解floyd的逐个点处理 例题

      6. 二分答案对于路径长度和其他条件的单调性处理 如4中例题

      7. 分清SPFA(没死透)和Dij两者各自的优势,注意负环

      8. 在最小生成树中,注意prim和kruskal各自的优势 例题1 例题2

      9. 差分约束 SPFA的独特优势(牢记系统约束) 例题

      10. 在连通性中巧用度(即入度和出度) 例题

      11. 善于建超级原点

      (欢迎评价添加)

      拓展性模板

      在二分图中,匈牙利算法虽好,但是毕竟抵不过网络流做法,这里是dinic模板

    #include<bits/stdc++.h>
    #define maxn 10008
    using namespace std;
    int n,m,head[maxn],s,t,cent=1,d[maxn],maxflow;
    int min(int a,int b){return a<b?a:b;}
    const int inf=1<<30;
    struct node{
        int next,to,w;
    }edge[maxn<<5];
    queue<int >q;
    
    void add(int u,int v,int w){
        edge[++cent]=(node){head[u],v,w};head[u]=cent;
        edge[++cent]=(node){head[v],u,0};head[v]=cent;
    }
    
    bool bfs(){
        memset(d,0,sizeof d);
        while(q.size()) q.pop();
        q.push(s),d[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=edge[i].next){
                int y=edge[i].to;
                if(edge[i].w&&!d[y]){
                    q.push(y);d[y]=d[x]+1;
                    if(y==t) return 1;
                }
            }
        }
        return 0;
    }
    
    int Dinic(int x,int flow){
        if(x==t) return flow;
        int rest=flow,k,y;
        for(int i=head[x];i;i=edge[i].next){
            if(edge[i].w&&d[y=edge[i].to]==d[x]+1){
                k=Dinic(y,min(rest,edge[i].w));
                edge[i].w-=k;
                edge[i^1].w+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    
    int main(){
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,a,b,w;i<=m;i++){
            scanf("%d%d%d",&a,&b,&w);
            add(a,b,w);
        }
        int flow=0;
        while(bfs())
            while(flow=Dinic(s,inf)) maxflow+=flow;
        printf("%d",maxflow);
    }

      

      缩点

      在联通性中,缩点是必要的

    #include<bits/stdc++.h>
    #define maxn 10007
    using namespace std;
    int n,m,head[maxn],a[maxn],cent,stackk[maxn],cnt,tot[maxn],col[maxn];
    int dfn[maxn],low[maxn],t,vis[maxn],top,root[maxn],ans;
    inline int max(int a,int b){return a>b?a:b;}
    inline int min(int a,int b){return a<b?a:b;}
    struct node{
        int next,to,from;
    }edge[maxn<<5];
    
    void add(int u,int v){
        edge[++cent]=(node){head[u],v,u};head[u]=cent;
    }
    
    void Tarjan(int x){
        dfn[x]=low[x]=++t;vis[x]=1;
        stackk[++top]=x;
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].to;
            if(!dfn[y]){
                Tarjan(y);
                low[x]=min(low[x],low[y]);
            }else if(vis[y]) low[x]=min(low[x],dfn[y]);
        }
        if(low[x]==dfn[x]){
            cnt++;int z;
            do{
                z=stackk[top--];
                col[z]=cnt;
                vis[z]=0;
                tot[cnt]+=a[z];
            }while(z!=x);
        }
    }
    
    void dp(int x,int fa){
        root[x]=tot[x];int ol=0;
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].to;
            if(y==fa) continue;
            dp(y,x);
            ans=max(ans,root[y]+root[x]);
            ol=max(ol,root[y]);
        }
        root[x]+=ol;
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1,a,b;i<=m;i++){
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) Tarjan(i);
        }
        memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++){
            int x=edge[i].from,y=edge[i].to;
            if(col[x]!=col[y]){
                add(col[x],col[y]);
            }
        }
        for(int i=1;i<=cnt;i++){
            if(root[i]) continue;
            dp(i,0);
            ans=max(root[i],ans);
        }
        printf("%d",ans);
        return 0;
    }

      之后还有许多基础性的知识在以后会看到。

    别困在自己的盒子里,别让自己成为世界都在议论的那只猫。
  • 相关阅读:
    perl glob 循环 注意事项
    Alacarte——gnome3的菜单编辑器
    arch更新pacman到4.0注意事项
    top命令中的排序
    兰州大学分子生态研究所——实验室主页
    解决gdm鼠标主题丑陋的方法
    小小输入法的安装
    linux下的双显卡切换
    使用jQuery AJax 与 asp.net ashx 结合使用
    sql语句控制时间的显示格式语句
  • 原文地址:https://www.cnblogs.com/waterflower/p/10408643.html
Copyright © 2011-2022 走看看