Loading

简单图论树论

1.图的存储与遍历

//链式前向星存储
int cnt,h[maxn];
struct edge{int to,nxt,val;}e[maxm];
void addedge(int u,int v,int val)
{
    e[++cnt]=(edge){v,h[u],val};
    h[u]=cnt;
}
//遍历
for(int i=h[u];i;i=e[i].nxt)
{
    int p=e[i].to;
    //...
}

2.最小生成树

2.1 无向图最小生成树

2.1.1 Kruskal算法

struct edge{int u,v,val;}e[400010];//单纯存边,这不是链式前向星
void init(){for(int i=1;i<=m;i++){fa[i]=i;siz[i]=1;}}
int find(int xx){return fa[xx]==xx?xx:fa[xx]=find(fa[xx]);}
void merge(int xx,int yy)
{
    int fx=find(xx),fy=find(yy);
    if(fx==fy)return;
    if(siz[fx]<siz[fy]){fa[fx]=fy;siz[fy]+=siz[fx];fa[xx]=fy;}
    else{fa[fy]=fx;siz[fx]+=siz[fy];fa[yy]=fx;}
}
bool query(int xx,int yy){return find(xx)==find(yy);}
bool cmp(edge u,edge v){return u.val<v.val;}
int kruskal()
{
    int ans=0;sort(e+1,e+m+1,cmp);init();
    for(int i=1;i<=m;i++)
        if(!query(e[i].u,e[i].v))
        {
            merge(e[i].u,e[i].v);
            ans+=e[i].val;
        }
    return ans;
}

2.1.2 Prim算法(堆优化)

int prim()
{
    int ans=0;
    memset(dis,0x3f,sizeof(dis));
    q.push(make_pair(0,1));
    while(!q.empty())
    {
        int u=q.top().second,val=q.top().first;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        ans+=val;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>e[i].val)
            {
                dis[p]=e[i].val;
                q.push(make_pair(dis[p],p));
            }
        }
    }
    return ans;
}

2.2 严格次小生成树

2.3 有向图最小生成树(最小树形图)

3.最短路

3.1 Floyd算法

memset(map,0x3f,sizeof(map));
for(int i=1;i<=n;i++)map[i][i]=0;
for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	    if(map[i][k]<0x3f3f3f3f&&map[k][j]<0x3f3f3f3f&&map[i][j]>map[i][k]+map[k][j])
		map[i][j]=map[i][k]+map[k][j];
for(int i=1;i<=n;i++)
    if(map[i][i]<0)//有负环
    {
	printf("NEGATIVE CYCLE\n");
	return 0;
    } 
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=n;j++)
	if(map[i][j]==0x3f3f3f3f)//不连通
	    printf("INF ");
	else
	    printf("%d ",map[i][j]); 
    printf("\n");
}

3.2 Dijkstra算法

void dijkstra(int s)
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;q.push(make_pair(0,s));
    while(!q.empty())
    {
        int u=q.top().second;q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>dis[u]+e[i].val)
            {
                dis[p]=dis[u]+e[i].val;
                q.push(make_pair(dis[p],p));
            }
        }
    }
}

3.3 SPFA算法

void spfa()
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;q.push(s);vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();vis[u]=0;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>dis[u]+e[i].val)
            {
                dis[p]=dis[u]+e[i].val;
                if(!vis[p])
                {
                    vis[p]=1;
                    q.push(p);
                }
            }
        }
    }
}

3.4 Johnson算法

bool spfa()
{
    memset(pot,0x7f,sizeof(pot));
    pot[n+1]=0;spfaq.push(n+1);vis[n+1]=1;
    while(!spfaq.empty())
    {
        int u=spfaq.front();spfaq.pop();vis[u]=0;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(pot[p]>pot[u]+e[i].val)
            {
                pot[p]=pot[u]+e[i].val;
                if(!vis[p])
                {
                    if(++pathcnt[p]>=n+1)return 1;
                    vis[p]=1;
                    spfaq.push(p);
                }
            }
        }
    }
    return 0;
}
void dijkstra(int s)
{
    memset(dis,0x7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;q.push(make_pair(0,s));
    while(!q.empty())
    {
        int u=q.top().second;q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>dis[u]+e[i].val+pot[u]-pot[p])
            {
                dis[p]=dis[u]+e[i].val+pot[u]-pot[p];
                q.push(make_pair(dis[p],p));
            }
        }
    }
}
//main函数里
if(spfa()){printf("-1\n");return 0;}
for(int i=1;i<=n;i++)dijkstra(i);

4.负环、差分约束与传递闭包

4.1 对负环的判断

bool spfa()
{
    memset(dis,0x7f,sizeof(dis));
    memset(pathcnt,0,sizeof(pathcnt));
    memset(vis,0,sizeof(vis));
    dis[1]=0;q.push(1);vis[1]=1;pathcnt[1]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>dis[u]+e[i].val)
            {
                dis[p]=dis[u]+e[i].val;
                pathcnt[p]=pathcnt[u]+1;
                if(pathcnt[p]>=n)return 1;
                if(!vis[p])
                {
                    vis[p]=1;
                    q.push(p);
                }
            }
        }
    }
    return 0;
}

4.2 差分约束系统

bool spfa()
{
    memset(dis,0x7f,sizeof(dis));
    dis[s]=0;q.push(s);vis[s]=1;pathcnt[s]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(int i=h[u];i;i=e[i].nxt)
        {
            int p=e[i].to;
            if(dis[p]>dis[u]+e[i].val)
            {
                dis[p]=dis[u]+e[i].val;
                pathcnt[p]=pathcnt[u]+1;
                if(pathcnt[p]>=n+1)return 1;
                if(!vis[p])
                {
                    vis[p]=1;
                    q.push(p);
                }
            }
        }
    }
    return 0;
}
//main函数里
n=read();m=read();s=n+1;
for(int i=1;i<=m;i++)
{
    int v=read(),u=read(),val=read();
    addedge(u,v,val);
}
for(int i=1;i<=n;i++)addedge(s,i,0);
if(spfa())printf("NO\n");
else for(int i=1;i<=n;i++)printf("%d ",dis[i]);

4.3 传递闭包

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	    if(map[i][k]&&map[k][j])
		map[i][j]=1;

5.LCA

5.1 倍增法

void dfs(int u,int fa)
{
    anc[u][0]=fa;dep[u]=dep[fa]+1;
    for(int i=1;i<=lg2[dep[u]];i++)anc[u][i]=anc[anc[u][i-1]][i-1];
    for(int i=h[u];i;i=e[i].nxt)
    {
        int p=e[i].to;
        if(p!=fa)dfs(p,u);
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    while(dep[u]<dep[v])v=anc[v][lg2[dep[v]-dep[u]]];
    if(u==v)return u;
    for(int k=lg2[dep[u]];k>=0;k--)
        if(anc[u][k]!=anc[v][k])
        {
            u=anc[u][k];
            v=anc[v][k];
        }
    return anc[u][0];
}
//预处理
for(int i=2;i<=n;i++)lg2[i]=lg2[i/2]+1;
dfs(s,0);

5.2 RMQ做法

5.3 Tarjan算法

6.Tarjan算法及其应用

6.1 强连通分量及其缩点

6.2 无向图的割点

6.3 无向图的割边(桥)

6.4 边双连通分量及其缩点

6.5 点双联通分量及其缩点

6.6 2-SAT问题

7. 欧拉回路

8. 树的同构

posted @ 2021-07-11 23:06  pjykk  阅读(43)  评论(0编辑  收藏  举报