图论各种模板

(1) 建图
邻接表
struct o
{
    int y,v,next;//y:该边终点编号  v:权值  next:同起点下条边编号 
}e[...];//边表 
int lin[...];//起点表 lin[i]表示由i出去第一条边的下标 
int len=0;//表示有len条边
void insert(int xx,int yy,int zz)
{
    e[++len].next=lin[xx];
    lin[xx]=len;
    e[len].y=yy;
    e[len].v=zz;
}
void init()
{
    cin>>n>>m;
    memset(e,0,sizeof(e));
    memset(lin,0,sizeof(lin));
    for(int i=1;i<=n;i++)
    {
        int xx,yy,zz;
        cin>>xx>>yy>>zz;
        insert(xx,yy,zz);
        insert(yy,xx,zz);
     }
}

(2) 遍历
1.邻接矩阵的dfs
void dfs(int k)
{
    for(int i=1;i<=n;i++)
     if(a[k][i] && !vis[i])
     {
         vis[i]=1;
        dfs(i); 
     }
}
2.邻接表的dfs
void dfs(int k)
{
    for(int i=lin[k];i;i=e[i].next)
     if(!vis[e[i].y])
     {
         vis[e[i].y]=1;
         dfs(e[i].y);
     }
}
int main()
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
     if(!vis[i])
      dfs(i);
    //求无向的连通分量 
    sumn=0;
    for(int i=1;i<=n;i++)
     if(!vis[i])
     {
         sumn++;
         dfs(i);
     }
    cout<<sumn<<endl; 
}
3.邻接矩阵的bfs
void bfs(int i)
{
    memset(q,0,sizeof(q));
    int head=0,tail=1;
    q[1]=i; vis[i]=1;
    while(head<tail)
    {
        k=q[++head];
        cout<<k;
        for(int j=1;j<=n;j++)
         if(a[k][j] && !vis[j])
         {
             q[++tail]=j;
             vis[j]=1;
         }
    }
}
4.邻接表的bfs 
void bfs(int k)
{
    int head=0,tail=1;
    q[1]=k;
    while(head++<tail)
    {
        for(int i=link[q[head]];i;i=a[i].next)
         if(!vis[a[i].y])
         {
             vis[a[i].y]=1;
             q[++tail]=a[i].y;
         }
    }
}

(3) 最短路

1.dijistra//不用堆优化
for(int i=1;i<=n;i++)
 dis[i]=a[st][i];  
memset(vis,0,sizeof(vis));  
vis[st]=1;
dis[st]=0; 
for(int _=1;_<n;_++)
{        
    int min=MAXX,mini;       
     for(int i=1;i<=n;i++)        
       if(!vis[i] && dis[i]<minn)
       minn=dis[i],mini=i;      
     if(!k) break;      
      vis[k]=1;      
      for(int i=1;i<=n;i++) 
      if(!vis[i]&&dis[i]>dis[mini]+a[mini][i])
       dis[i]=dis[mini]+a[mini][i]; 
}
//用堆优化
typedef pair<int,int>pii; 
priority_queue <pii,vector<pii>,greater<pii>>q;      
memset(dis,20,sizeof(dis));  
dis[1]=0;
q.push(make_pair(0,1));  
while(!q.empty())
{          
    pii t=q.top();q.pop();
    int x=t.second,vv=t.first;        
      if(vis[x]) continue;          
    vis[x]=1; 
     for(int i=linkk[x];i;i=e[i].next)            
     if(dis[e[i].y]>vv+e[i].v)
     {
         dis[e[i].y]=vv+e[i].v;
        q.push(make_pair(dis[e[i].y],e[i].y)); 
     } 
       
}

2.SPFA
memset(vis,0,sizeof(vis));
queue <int>q; 
q.push(st);      
dis[st]=0;      
vis[st]=1;      
while(!q.empty())
{         
     int x=q.front();
    q.pop();           
    vis[x]=0; 
    for(int i=linkk[x];i;i=e[i].next) 
     if(dis[e[i].y]>dis[x]+e[i].v)
    {              
         dis[e[i].y]=dis[x]+e[i].v; 
          if (!vis[e[i].y])
         q.push(e[i].y),vis[e[i].y]=1; 
     } 

3.floyed
 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]); 

(4)最小生成树 

1.Kruskal
void getfa(int x)
{
    if(x==fa[x])
     return x;
    return fa[x]=getfa(fa[x]);
}
sort(e+1,e+len+1,mycmp(x.v<y.v));      
for(int i=1;i<=len;i++)
{           
    int x=getfa(e[i].x),y=getfa(e[i].y); 
     if(x!=y)
     fa[x]=y,ans+=e[i].v;

cout<<ans; 

2.Prim
void Prim()
{     
    int now=1;
    memset(dis,20,sizeof(dis)); 
    for(int i=linkk[1];i;i=e[i].next)
      dis[e[i].y]=min(dis[e[i].y],e[i].v);   
      for (int _=1;_<n;_++)
    {         
        int minn=MAXX;        
         vis[now]=1;      
           for(int i=1;i<=n;i++) 
           if(!vis[i]&&minn>dis[i])
        minn=dis[i],now=i;        
         ans+=minn; 
        for(int i=linkk[now];i;i=e[i].next)
         if(!vis[e[i].y]&&dis[e[i].y]>e[i].v)
          dis[e[i].y]=e[i].v; 
    }

(5)拓扑排序
void topo()
{
    int i,j,now;
    queue<int> q;
    for(i=1;i<=n;i++)
     if(!ind[i])
      q.push(i);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        ans[++cnt]=now;
        for(i=last[now];i;i=e[i].next)
        {
            ind[e[i].to]--;
            if(!ind[e[i].to])
             q.push(e[i].to);
        }
    }
    if(cnt!=n)
     puts("-1");
    else
     for(i=1;i<=n;i++)
      cout<<ans[i]<<' ';

(6)树的直径
void bfs(int s)
{
    int i,j,now;
    queue<int> q;
    memset(v,0,sizeof(v));
    memset(dis,0,sizeof(dis));
    q.push(s); v[s]=1;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(i=last[now];i;i=e[i].next)
         if(!v[e[i].to])
         {
             v[e[i].to]=true;
            dis[e[i].to]=dis[now]+e[i].v;
            q.push(e[i].to); 
         }
    }
    for(i=1,ans=0;i<=n;i++)
     if(dis[i]>ans)
     {
         ans=dis[i];
         point=i;
     }
}
int main()
{
    bfs(s); bfs(point);

(7)树的重心
void dp(int x,int fa)
{
    size[x]=1;
    for(int i=0;i<e[x].size();i++)
    {
        int y=e[x][i];
        if(y==fa)
         continue;
        dp(y,x);
        size[x]+=size[y];
        mx[x]=max(mx[x],size[y]);
    }
    mx[x]=max(mx[x],n-size[x]);
    if(mx[x]<mx[ans])
     ans=x;
    if(mx[x]==mx[ans] && x<ans)
     ans=x;

(8)基环树
void getloop(int u)
{
    vis[u]=++vs;
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa[u])
         continue;
        if(vis[v])
        {
            if(vis[v]<vis[u])
             continue;
            loop[++cnt]=v;
            for(;v!=u;v=fa[v])
             loop[++cnt]=fa[v];
        }
        else
         fa[v]=u,getloop(v);
    }
}
(9)最近公共祖先
1.倍增法
void dfs(int u,int d)
{
    depth[u]=d;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[0][u])
         continue;
        fa[0][v]=u;
        dfds(v,d+1);
    }
    return ;
}
void init()
{
    fa[0][1]=-1;
    dfs(1,0);
    for(int i=1;1<<i<n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(fa[i-1][j]<0)
             fa[i][j]=-1;
            else
             fa[i][j]=fa[i-1][fa[i-1][j]];
        }
    }
    return ;
}
int lca(int u,int v)
{
    if(depth[u]>depth[v])
     swap(u,v);
    for(int d=depth[v]-depth[u],i=0;d;d>>=1,i++)
     if(d&1) v=fa[i][v];
    if(u==v) return u;
    for(int i=max_logn-1;i>=0;i--)//max_logn=20 / 21
     if(fa[i][u]!=fa[i][v])
     {
         u=fa[i][u];
         v=fa[i][v];
     }
    return fa[0][u];
}
2.tarjan
int find(int x)
{
    int y=x;
    while(set[y].parent!=y)
     y=set[y].parent;
    while(x!=y)
    {
        int temp=set[x].parent;
        set[x].parent=y;
        x=temp;
    }
    return y;
}
void tarjan(int u)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(vis[v]) continue;
        tarjan(v);
        fa[v]=u;
    }
    for(int i=h[u];i!=-1;i=arr[i].next)
    {
        v=arr[i].to;
        if(vis[v])
         ans[arr[i].id]=find(v);
    }
    return ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值