• 复习2


    1.最小生成树

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,num,head[5010],ans,dis[5010];
    bool vis[5010];
    struct node{
        int to,v,pre;
    }e[400010];
    void Insert(int from,int to,int v){
        e[++num].pre=head[from];
        e[num].to=to;
        e[num].v=v;
        head[from]=num;
    }
    void Prim(){
        memset(dis,127/3,sizeof(dis));
        dis[1]=0;
        for(int i=1;i<=n;i++){
            int minn=0x7fffffff,k=0;
            for(int j=1;j<=n;j++){
                if(!vis[j]&&dis[j]<minn){
                    minn=dis[j];
                    k=j;
                }
            }
            if(minn==0x7fffffff)break;
            vis[k]=1;
            for(int j=head[k];j;j=e[j].pre){
                int f=e[j].to;
                if(!vis[f])
                    dis[f]=min(dis[f],e[j].v);
            }
        }
        for(int i=1;i<=n;i++)ans+=dis[i];
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            Insert(x,y,z);Insert(y,x,z);
        }
        Prim();
        printf("%d",ans);
    }
    Prim算法
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,num,head[5010],fa[5010];
    struct node{
        int x,y,z;
    }E[200010];
    bool cmp(node a,node b){
        return a.z<b.z;
    }
    int find(int x){
        if(x==fa[x])return x;
        return fa[x]=find(fa[x]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)fa[i]=i;
        int x,y,z,cnt=0,ans=0;
        for(int i=1;i<=m;i++)scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].z);
        sort(E+1,E+m+1,cmp);
        for(int i=1;i<=m;i++){
            int f1=find(E[i].x),f2=find(E[i].y);
            if(f1!=f2){
                fa[f1]=f2;
                ans+=E[i].z;
                cnt++;
            }
            if(cnt==n-1)break;
        }
        if(cnt<n-1)puts("orz");
        else printf("%d",ans);
    }
    kruskal算法

    2.最短路

    struct Node{
        int id,dist;
        bool operator < (const Node b)const{
            return dist>b.dist;
        }
    };
    bool Dij(int limit){
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        priority_queue<Node>q;
        q.push(make_node(s,0));
        dis[s]=0;
        while(!q.empty()){
            Node cur=q.top();q.pop();int now=cur.id;
            if(w[now]>limit)continue;
            if(vis[now])continue;
            vis[now]=1;
            for(int i=head[now];i;i=e[i].pre){
                int to=e[i].to;
                if(w[to]>limit)continue;
                if(dis[to]>dis[now]+e[i].v){
                    dis[to]=dis[now]+e[i].v;
                    q.push(make_node(to,dis[to]));
                }
            }
        }
        return dis[t]<=g;
    }
    堆优化Dij
    bool spfa(int limit){
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        deque<int>q;
        q.push_back(s);
        dis[s]=0;vis[s]=1;
        while(!q.empty()){
            int now=q.front();q.pop_front();vis[now]=0;
            if(w[now]>limit)continue;
            for(int i=head[now];i;i=e[i].pre){
                int to=e[i].to;
                if(w[to]>limit)continue;
                if(dis[to]>dis[now]+e[i].v){
                    dis[to]=dis[now]+e[i].v;
                    if(!vis[to]){
                        vis[to]=1;
                        if(!q.empty()&&dis[to]<dis[q.front()])q.push_front(to);
                        else q.push_back(to);
                    }
                }
            }
        }
        return dis[t]<=g;
    }
    SLF优化spfa

    3.匈牙利算法

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 1000010
    int n,link[maxn],num,head[maxn*2];
    bool vis[maxn];
    struct node{
        int to,pre;
    }e[maxn*2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    bool dfs(int x){
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(!vis[to]){
                vis[to]=1;
                if(!link[to]||dfs(link[to])){
                    link[to]=x;return 1;
                }
            }
        }
        return 0;
    }
    int main(){
        scanf("%d",&n);
        int x,y;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            if(x<=n)Insert(x,i);
            if(y<=n)Insert(y,i);
        }
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            if(!dfs(i)){
                printf("%d",i-1);
                return 0;
            }
        }
        printf("%d",n);
        return 0;
    }
    最大匹配数

    4.Tarjan算法(强联通分量,桥,割)

    无向图割点
    对该图进行一次 Tarjan 算法(这里注意在搜索树中把无向边当做有向边看。即LOW[u]=min(LOW[u],DFN[v])(v 是 u 的祖先)的条件变为(v 是 u 的祖先且 v 不是 u 的父亲))这样之后枚举搜索树上的所有边(u,v),若存在 LOW[v]>=DNF[u],则 u 是割点。
    无向图割边
    对该图进行一次 Tarjan 算法(这里注意在搜索树中把无向边当做有向边看。即LOW[u]=min(LOW[u],DFN[v])(v 是 u 的祖先)的条件变为(v 是 u 的祖先且 v 不是 u 的父亲))这样之后枚举搜索树上的所有边(u,v),若存在 LOW[v]>DNF[u],则(u,v)为割边。

    #include<iostream>
    #include<cstdio>
    #define MAXn 100000
    #define MAXm 2000000
    using namespace std;
    int dfn[MAXn],low[MAXn],head[MAXm],st[MAXn],belong[MAXn];
    bool in_st[MAXn];
    int ans,n,m,num,s_num,cnt,group_num;
    struct node{
        int to,pre;
    }e[MAXm];
    void Insert(int from,int to){
        e[++num].pre=head[from];
        e[num].to=to;
        head[from]=num;
    }
    void group(int u){
        cnt++;st[++s_num]=u;dfn[u]=low[u]=cnt;in_st[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(!dfn[v]){
                group(v);
                if(low[v]<low[u])low[u]=low[v];
            }
            else if(dfn[v]<low[u])
                if(in_st[v])
                low[u]=dfn[v];
        }
        if(dfn[u]==low[u]){
            group_num++;
            while(st[s_num]!=u){
                in_st[st[s_num]]=0;
                belong[st[s_num]]=group_num;
                s_num--;
            }
            in_st[u]=0;s_num--;
            belong[u]=group_num;
        }
    }
    int main(){
        freopen("Tarjan_group.txt","r",stdin);
        scanf("%d%d",&n,&m);int x,y;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i])group(i);
        }
        for(int i=1;i<=n;i++){
            printf("%d ",belong[i]);
        }printf("
    %d",group_num);
    }
    Tarjan_group模板
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int dfn[maxn],low[maxn],cnt,ans;
    bool cut[maxn];
    int n,m,num,head[maxn];
    struct node{
        int from,to,pre;
    }e[maxn*2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].from=from;
        e[num].pre=head[from];
        head[from]=num;
    }
    void Tarjan(int u,int father){
        int rc=0;
        cnt++;dfn[u]=low[u]=cnt;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(!dfn[v]){
                Tarjan(v,father);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]&&u!=father)cut[u]=1;
                if(u==father)rc++;
            }
            low[u]=min(low[u],dfn[v]);
        }
        if(u==father&&rc>=2)cut[u]=1;
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&m);
        int x,y;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);Insert(y,x);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])Tarjan(i,i);
        for(int i=1;i<=n;i++)if(cut[i])ans++;
        printf("%d
    ",ans);
        for(int i=1;i<=n;i++)if(cut[i])printf("%d ",i);
    }
    Tarjan割点
    #include<iostream>
    using namespace std;
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define N 201
    vector<int>G[N];
    int n,m,low[N],dfn[N];
    bool is_cut[N];
    int father[N];
    int tim=0;
    void input()
    {
        scanf("%d%d",&n,&m);
        int a,b;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);/*邻接表储存无向边*/
            G[b].push_back(a);
        }
    }
    void Tarjan(int i,int Father)
    {
        father[i]=Father;/*记录每一个点的父亲*/
        dfn[i]=low[i]=tim++;
        for(int j=0;j<G[i].size();++j)
        {
            int k=G[i][j];
            if(dfn[k]==-1)
            {
                Tarjan(k,i);
                low[i]=min(low[i],low[k]);
            }
            else if(Father!=k)/*假如k是i的父亲的话,那么这就是无向边中的重边,有重边那么一定不是桥*/
                low[i]=min(low[i],low[k]);
        }
    }
    void count()
    {
        int rootson=0;
        Tarjan(1,0);
        for(int i=2;i<=n;++i)
        {
            int v=father[i];
            if(v==1)
            rootson++;/*统计根节点子树的个数,根节点的子树个数>=2,就是割点*/
            else{
                if(low[i]>=dfn[v])/*割点的条件*/
                is_cut[v]=true;
            }
        }
        if(rootson>1)
        is_cut[1]=true;
        for(int i=1;i<=n;++i)
        if(is_cut[i])
        printf("%d
    ",i);
        for(int i=1;i<=n;++i)
        {
            int v=father[i];
            if(v>0&&low[i]>dfn[v])/*桥的条件*/
            printf("%d,%d
    ",v,i);
        }
        
    }
    int main()
    {
        input();
        memset(dfn,-1,sizeof(dfn));
        memset(father,0,sizeof(father));
        memset(low,-1,sizeof(low));
        memset(is_cut,false,sizeof(is_cut));
        count();
        return 0;
    }
    求桥,割点

    5.lca

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 500010
    using namespace std;
    int n,q,root,fa[maxn][22],dep[maxn],num,head[maxn];
    struct node{int to,pre;}e[maxn*2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void dfs(int now,int father){
        fa[now][0]=father;
        dep[now]=dep[father]+1;
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(to==father)continue;
            dfs(to,now);
        }
    }
    int lca(int a,int b){
        if(dep[a]!=dep[b]){
            if(dep[a]<dep[b])swap(a,b);
            for(int i=18;i>=0;i--)
                if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
        }
        if(a==b)return a;
        for(int i=18;i>=0;i--)
            if(fa[a][i]!=fa[b][i])
                a=fa[a][i],b=fa[b][i];
        if(a==b)return a;
        return fa[a][0];
    }
    /*int get(int a,int delta){
        for(int i=0;i<=21;i++){
            if(delta&(1<<i))a=fa[a][i];
        }return a;
    }
    int lca(int a,int b){
        if(dep[a]<dep[b])swap(a,b);
        a=get(a,dep[a]-dep[b]);
        if(a==b) return a;
        for(int i=21;i>=0;i--)
            if(fa[a][i]!=fa[b][i])
                a=fa[a][i],b=fa[b][i];
        return fa[a][0];
    }*/
    int main(){
        scanf("%d%d%d",&n,&q,&root);
        int x,y;
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);Insert(y,x);
        }
        dfs(root,root);
        for(int j=1;j<=20;j++)
            for(int i=1;i<=n;i++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
        while(q--){
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
    }
    倍增lca(两种跳法均可)
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxn 1000010
    int n,s1,s2,head[maxn*2],num,son[maxn],sz[maxn],top[maxn],fa[maxn],dep[maxn];
    struct node{
        int to,pre;
    }e[maxn*2];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void dfs1(int u,int father){
        sz[u]=1;
        fa[u]=father;
        dep[u]=dep[father]+1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(v==father)continue;
            dfs1(v,u);
            sz[u]+=sz[v];
            if(!son[u]||sz[v]>sz[son[u]])son[u]=v;
        }
    }
    void dfs2(int u,int father){
        top[u]=father;
        if(son[u])dfs2(son[u],father);
        else return;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    int lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])return x;
        else return y;
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d",&n);
        int x,y;
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            Insert(y,x);
            Insert(x,y);
        }
        scanf("%d%d",&s1,&s2);
        dfs1(1,0);
        dfs2(1,1);
        printf("%d",lca(s1,s2));
    }
    树剖lca

    6.树上差分

    7.欧拉回路

    定义:给定无孤立结点图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次,称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。

    欧拉回路存在的充要条件: 每个点的度为偶数(无向图) 每个点的入度出度相等(有向图)

    欧拉路存在的必要条件: 有且仅有两个点的度为奇数(无向图) 总的入度和等于总的出度和,有且仅有两个点的入度、出度差为1,其他点相等(有向图)

    void eular(int x){
        for(int i=1;i<=52;i++){
            if(cxt[x][i]){
                cxt[x][i]=cxt[i][x]=0;
                eular(i);
            }
        }
        s[++cnt]=x;
    }

    8.拓扑排序

  • 相关阅读:
    内联函数和宏
    python面向对象高级:@property
    python面向对象高级:__slots__
    Python哈希表的例子:dict、set
    python数据结构之哈希表
    python数据结构之队列
    python数据结构之堆栈
    python数据结构之链表
    分治法及其python实现例子
    查找算法:二分法查找及其python实现案例
  • 原文地址:https://www.cnblogs.com/thmyl/p/7792402.html
Copyright © 2020-2023  润新知