zoukankan      html  css  js  c++  java
  • 【模板】图论

    一、生成树

     洛谷模板最小生成树【跑的还算快的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 5020
    #define M 200008
    using namespace std;
    
    int n,m,ans;
    
    int tot;
    
    int fa[N];
    
    struct E{
        int x,y,z;
    }e[M];
    
    bool cmp(E a,E b){
        return a.z<b.z;
    }
    
    int f(int x){
        return fa[x]==x?x:fa[x]=f(fa[x]);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
        for(int i=1;i<=n;i++)fa[i]=i;
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++){
            int x=e[i].x,y=e[i].y;
            int fx=f(x),fy=f(y);
            if(fx!=fy){
                fa[fx]=fy;
                ans+=e[i].z;
                if(++tot==n-1)break;
            }
        }
        if(tot!=n-1)cout<<"orz
    ";
        else printf("%d
    ",ans);
        return 0;
    }
    kruskal
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 5020
    #define M 200009
    #define inf 10000000
    using namespace std;
    
    int n,m,sumedge,ans,dis[N],head[N];
    
    bool vis[N];
    
    struct Edge{
        int x,y,z,nxt;
        Edge(int x=0,int y=0,int z=0,int nxt=0):
            x(x),y(y),z(z),nxt(nxt){}
    }edge[M<<1];
    
    void add(int x,int y,int z){
        edge[++sumedge]=Edge(x,y,z,head[x]);
        head[x]=sumedge;
    }
    
    void prim(){
        memset(dis,0x3f,sizeof(dis));
        dis[1]=0;
        for(int i=1;i<=n;i++){
            int u=-1,mn=inf;
            for(int j=1;j<=n;j++){
                if(dis[j]<mn&&!vis[j]){
                    u=j;mn=dis[j];
                }
            }
            if(u==-1){
                ans=-1;return;
            }
            vis[u]=true;ans+=dis[u];
            for(int x=head[u];x;x=edge[x].nxt){
                int v=edge[x].y;
                if(dis[v]>edge[x].z)dis[v]=edge[x].z;
            }
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);add(y,x,z);
        }
        prim();
        if(ans==-1)cout<<"orz
    ";
        else cout<<ans;
        return 0;
    }
    prim

    二、最短路

    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)dis[i][i]=0;
    for(int k=1;k<=n;k++)
     for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
       dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    floyed
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 10009
    #define inf 2147483647
    using namespace std;
    
    int n,m,s,sumedge;
    int dis[maxn],vis[maxn],head[maxn];
    
    struct Edge{
        int x,y,z,nxt;
        Edge(int x=0,int y=0,int z=0,int nxt=0):
            x(x),y(y),z(z),nxt(nxt){}
    }edge[maxn*51];
    
    void add(int x,int y,int z){
        edge[++sumedge]=Edge(x,y,z,head[x]);
        head[x]=sumedge;
    }
    
    void di(){
        for(int i=1;i<=n;i++)dis[i]=inf;
        dis[s]=0;
        for(int i=1;i<=n;i++){
            int k,mn=inf;
            for(int j=1;j<=n;j++){
                if(!vis[j]&&dis[j]<mn){
                    mn=dis[j];k=j;
                }
            }
            if(mn==inf)break;
            vis[k]=true;
            for(int j=head[k];j;j=edge[j].nxt){
                int v=edge[j].y;
                if(!vis[v]&&dis[v]>dis[k]+edge[j].z)
                 dis[v]=dis[k]+edge[j].z;
            }
        }
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&s);
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        di();
        for(int i=1;i<=n;i++)printf("%d ",dis[i]);
        return 0;
    }
    没有优化的dijkstra
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define N 100008
    using namespace std;
    
    int n,m,s;
    
    int sumedge;
    
    int head[N],dis[N],vis[N];
    
    struct Edge{
        int x,y,z,nxt;
        Edge(int x=0,int y=0,int z=0,int nxt=0):
            x(x),y(y),z(z),nxt(nxt){}
    }edge[N*5];
    
    struct node{
        int x,dis;
        bool operator < (node a) const{
            return dis>a.dis;
        }
    };
    
    priority_queue<node>q;
    
    void add(int x,int y,int z){
        edge[++sumedge]=Edge(x,y,z,head[x]);
        head[x]=sumedge;
    }
    
    void dijikstra(int x){
        while(!q.empty())q.pop();
        memset(dis,0x3f,sizeof(dis));
        dis[x]=0;
        q.push((node){x,0});
        while(!q.empty()){
            node now=q.top();q.pop();
            if(vis[now.x])continue;
            vis[now.x]=true;
            for(int i=head[now.x];i;i=edge[i].nxt){
                int v=edge[i].y;
                if(dis[v]>dis[now.x]+edge[i].z){
                    dis[v]=dis[now.x]+edge[i].z;
                    q.push((node){v,dis[v]}); 
                }
            }
        } 
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&s);
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        dijikstra(s);
        for(int i=1;i<=n;i++)
        if(dis[i]==0x3f3f3f3f)printf("2147483647 ");
        else 
        printf("%d ",dis[i]);
        return 0;
    }
    堆优化dijkstra
    void spfa(){
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        while(!q.empty())q.pop();
        dis[1]=0;vis[1]=true;q.push(1);
        while(!q.empty()){
            int now=q.front();q.pop();vis[now]=false;
            for(int i=head[now];i;i=edge[i].nxt){
                int v=edge[i].y;
                if(dis[v]>dis[now]+edge[i].z){
                    dis[v]=dis[now]+edge[i].z;
                    if(!vis[v]){
                        vis[v]=true;q.push(v);
                    }
                }
            }
        }
    }
    spfa

    三、二分图

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1020
    using namespace std;
    
    int n,m,e,ans,sumedge;
    
    int vis[N],match[N],head[N];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[N*N];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    bool dfs(int x){
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(!vis[v]){
                vis[v]=true;
                if(match[v]==0||dfs(match[v])){
                    match[v]=x;return true;
                }
            }
        }
        return false;
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&e);
        for(int i=1;i<=e;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            if(y>m||x>n)continue;
            add(x,y);
        }
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            if(dfs(i))ans++;
        }
        cout<<ans<<endl;
        return 0;
    }
    洛谷模板二分图匹配

     封锁阳光大学

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define maxn 10001
    #define maxm 100009
    #ifdef WIN32
    #define PLL "%I64d
    "
    #else
    #define PLL "%lld
    "
    #endif
    using namespace std;
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxm*2];
    
    int head[maxn],col[maxn],q[maxn];
    int sumedge,n,m,cnt1,x,y,cnt2,ans;
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        memset(col,-1,sizeof(col));
        for(int i=1;i<=n;i++){
            if(col[i]==-1){
                int h,t;h=t=1;col[i]=1;q[h]=i;
                while(h<=t){
                    int now=q[h++];
                     if(col[now]==1)cnt1++; else cnt2++;
                    for(int j=head[now];j;j=edge[j].nxt){
                        int v=edge[j].y;
                        if(col[v]==-1){
                            q[++t]=v;
                            col[v]=col[now]^1;
                        }
                        if(col[v]==col[now]){
                            printf("Impossible");
                            return 0;
                        }
                    }
                }
            }
            ans+=min(cnt1,cnt2);
            cnt1=cnt2=0;
        }
        printf(PLL,ans);
    }
    二分图判定

    四、LCA

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 500009
    using namespace std;
    
    int n,m,s,sumedge;
    int head[maxn],deep[maxn],size[maxn],dad[maxn],top[maxn];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    void dfs(int x){
        size[x]=1;deep[x]=deep[dad[x]]+1;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v==dad[x])continue;
            dad[v]=x;dfs(v);
            size[x]+=size[v];
        }
    }
    
    void dfs_(int x){
        int s=0;
        if(!top[x])top[x]=x;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=dad[x]&&size[v]>size[s])s=v;
        }
        if(s){
            top[s]=top[x];
            dfs_(s);
        }
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=dad[x]&&v!=s)dfs_(v);
        }
    }
    
    int lca(int x,int y){
        for(;top[x]!=top[y];){
            if(deep[top[x]]>deep[top[y]])swap(x,y);
            y=dad[top[y]];
        }
        if(deep[x]>deep[y])return y;
        return x;
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&s);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs(s);dfs_(s);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
        return 0;
    }
    树剖
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 500009
    using namespace std;
    
    int n,m,s,sumedge;
    int head[maxn],dad[maxn][25],deep[maxn];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    void dfs(int x){
        deep[x]=deep[dad[x][0]]+1;
        for(int i=0;dad[x][i];i++)
         dad[x][i+1]=dad[dad[x][i]][i];
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v==dad[x][0])continue;
            dad[v][0]=x;
            dfs(v);
        }
    }
    
    int lca(int x,int y){
        if(deep[x]>deep[y])swap(x,y);
        for(int i=20;i>=0;i--)if(deep[dad[y][i]]>=deep[x])y=dad[y][i];
        if(x==y)return x;
        for(int i=20;i>=0;i--)if(dad[x][i]!=dad[y][i])x=dad[x][i],y=dad[y][i];
        return dad[x][0];
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&s);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs(s);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
        return 0;
    }
    倍增

    五、tarjan

    洛谷模板

    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define maxn 1000006
    
    int n,m,sumedge,root,ans,tim;
    int low[maxn],dfn[maxn],iscut[maxn],head[maxn]; 
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    int min(int x,int y){
        return x<y?x:y;
    }
    
    void Tarjian(int x,int fa){
        dfn[x]=low[x]=++tim;int cnt=0;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v==fa)continue;
            if(dfn[v]==0){
                cnt++;
                Tarjian(v,x);
                low[x]=min(low[x],low[v]);
                if(low[v]>=dfn[x]&&x!=root&&iscut[x]==0)iscut[x]=true,ans++;
                if(x==root&&cnt>=2&&iscut[x]==0)iscut[x]=true,ans++;
            }else low[x]=min(low[x],dfn[v]);
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
         if(!dfn[i])root=i,Tarjian(i,i);
        printf("%d
    ",ans);
        for(int i=1;i<=n;i++) if(iscut[i]) printf("%d ",i);
        return 0;
    }
    割点
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 22000
    using namespace std;
    
    int n,sumedge,sumclr,top,tim,ans;
    int Stack[maxn],instack[maxn],low[maxn],dfn[maxn],bel[maxn],rd[maxn],head[maxn];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    void Tarjian(int x){
        Stack[++top]=x;instack[x]=true;
        low[x]=dfn[x]=++tim;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(instack[v])low[x]=min(low[x],dfn[v]);
            else if(!dfn[v]){
                Tarjian(v);
                low[x]=min(low[x],low[v]);
            }
        }
        if(low[x]==dfn[x]){
            sumclr++;
            while(Stack[top+1]!=x){
                bel[Stack[top]]=sumclr;
                instack[Stack[top]]=false;
                top--;
            }
        }
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int x;
            while(1){
                scanf("%d",&x);
                if(!x)break;
                add(i,x);
            }
        }
        for(int i=1;i<=n;i++)if(!dfn[i])Tarjian(i);
        for(int x=1;x<=n;x++){
            for(int i=head[x];i;i=edge[i].nxt){
                int v=edge[i].y;
                if(bel[x]!=bel[v])rd[bel[v]]++;
            }
        }
        for(int i=1;i<=sumclr;i++)if(!rd[i])ans++;
        printf("%d
    ",ans);
        return 0;
    }
    
    AC
    缩点

     洛谷:炸铁路

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define maxn 5202
    using namespace std;
    
    int n,m,sumedge,tim,cnt;
    int head[maxn],low[maxn],dfn[maxn];
    
    struct Ans{
        int x,y;
    }ans[maxn];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    bool cmp(Ans a,Ans b){
        if(a.x!=b.x)return a.x<b.x;
        return a.y<b.y;
    }
    
    void Tarjian(int x,int fa){
        low[x]=dfn[x]=++tim;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v==fa)continue;
            if(!dfn[v]){
                Tarjian(v,x);
                low[x]=min(low[x],low[v]);
                if(low[v]>dfn[x])ans[++cnt].x=x,ans[cnt].y=v;
            }else low[x]=min(low[x],dfn[v]);
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
         if(!dfn[i])Tarjian(i,i);
        sort(ans+1,ans+cnt+1,cmp);
        for(int i=1;i<=cnt;i++)
        printf("%d %d
    ",ans[i].x,ans[i].y);
        return 0;
    }
    
    AC
    割边

    注意图不一定连通

    六、结论/性质

    二分图:

    1.  最小点覆盖  = 最大匹配。

    2. 最大独立集  = 顶点总数 - 最大匹配。

    3. 最小边覆盖 = 顶点总数 - 最大匹配。

    4. 最小路径覆盖 = 顶点总数 - 最大匹配。


    1、图上两点之间的路径的最小边的最大值一定在最大生成树上

    2、树的直径:树上最远两点的距离

    3、树的重心:

    树的重心定义

    树中的一个点,删掉这个点,使得剩下的树所

    构成的森林中最大的子树节点数最少。

    树的重心推论

    1.设树上的一个点S,树上其余所有点到S点的

    距离之和最小,那么S就是重心。

    2.树的重心不唯一。

    然后可以依靠定义来求树的重心。

    首先以任意一个点,进行dfs,dfs过程中统计以

    每个点为根的子树中,一共含有多少节点。

    然后 总节点数 减去 子树的节点数 减去1(自己),

    就是它父亲那边点的数量。做差之后取最小值。

  • 相关阅读:
    画图工具Graphviz安装配置
    转:完善eclipse+pdt作php开发中的代码提示能力
    转:SVN 出现This client is too old to work with working copy...错误
    Codeforces Round #260 (Div. 2)C. Boredom(dp)
    three.js 源代码凝视(十四)Math/Sphere.js
    android项目中刷新activity界面
    中科燕园GIS外包---地铁GIS项目
    华为HCNA教程(笔记)
    HapiJS开发手冊
    《Java并发编程实战》第十四章 构建自己定义的同步工具 读书笔记
  • 原文地址:https://www.cnblogs.com/zzyh/p/7795410.html
Copyright © 2011-2022 走看看