4.29--4.30 图论

1、二叉堆的操作

(1)取出元素

(2)插入元素

(3)删除元素

//手写大根堆维护
#include<bits/stdc++.h>
using namespace std;
int heap[1000];
int up(int x)
{
    if(heap[x]<=heap[x/2])
    return 0;
    else
    {
        swap(heap[x],heap[x/2]);
        up(x/2);
    }
}
int down(int x)
{
    if(heap[x]>=heap[x*2]&&heap[x]>=heap[x*2+1])
    return 0;
    else
    if(heap[x*2]>heap[x*2+1])
    {
        swap(heap[x],heap[x*2]);
        down(x*2);
    }
    else
    {
        swap(heap[x],heap[x*2+1]);
        down(x*2+1);
    }
}
int m,od,x,n;
int main()
{
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&od);
        if(od==1)
        {
            printf("%d",heap[0]);
        }
        if(od==2)
        {
            scanf("%d",&x);
            n++;
            heap[n]=x;
            up(n);
        }
        if(od==3)
        {
            heap[0]=heap[n];
            n--;
            down(1);
        }
    }
    return 0;
}

手写大根堆

#include<bits/stdc++.h>
using namespace std;
priority_queue<int>heap;
int m,x,od;
int main()
{
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&od);
        if(od==1)
        printf("%d",heap.top());
        if(od==2)
        {
            scanf("%d",&x);
            heap.push(x);
        }
        if(od==3)
        {
            heap.pop();
        }
    }
    return 0;
}

大根堆优先队列维护

2、最小生成树

(1)prim算法 蓝白点思想

#include<bits/stdc++.h>
using namespace std;

const int maxn=10000+15;
int m,n,x,y,z,maxx,ans;
int edge[maxn][maxn],dis[maxn];
bool boo[maxn];
int main()
{
 scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);//加边
        edge[x][y]=edge[y][x]=z;
    }
    memset(dis,127/3,sizeof(dis));
    dis[1]=0;boo[1]=1;//由结点1开始生成最小生成树,boo[1]=1,表示结点1已经加入最小生成树
    for(int i=2;i<=n;i++){
        if(edge[1][i])
        dis[i]=min(dis[i],edge[1][i]);//更新和结点1相连的点的值
    }
    for(int i=1;i<=n-1;i++){//生成n-1条边
        maxx=0;
        for(int j=1;j<=n;j++){
            if(!boo[j])//找一个点没加入最小生成树并且距离已经生成的树的距离最小的
            if(!maxx||dis[maxx]>dis[j])
            maxx=j;
        }
        boo[maxx]=1;//将它加入最小生成树
        ans+=dis[maxx];//加入答案
        for(int j=1;j<=n;j++){//将它更新其他点到最小生成树的距离;
            if(!boo[j])
            if(edge[maxx][j])
            dis[j]=min(dis[j],edge[maxx][j]);
        }
    }
    printf("%d",ans);
    return 0;
}

prim

//prim的队列优化
#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
const int maxm=100000+15;
struct Edge
{
    int x,y,z,next;
    Edge(int x=0,int y=0,int z=0,int next=0):x(x),y(y),z(z),next(next) {}
}edge[maxm*2];
const bool operator < (const Edge &a,const Edge &b) //为了优先队列取边时,将权值最小的边先取出
{
    return a.z>b.z;
 }
int n,m;
int sumedge,head[maxn];
int ins(int x,int y,int z)
{
    edge[++sumedge]=Edge(x,y,z,head[x]);
    return head[x]=sumedge;
}
priority_queue <Edge> que;//优先队列 里面的内容是一个结构体 是没条边的x,y,z,next;
int ans;
bool boo[maxn];//标记有没有加入最小生成树
int main()
{
    scanf("%d%d",&n,&m);//输入n个点m条边
    for (int i=1;i<=m;i++)
    {
        int x,y,z;//输入起点,终点,权值
        scanf("%d%d%d",&x,&y,&z);
        ins(x,y,z);//链表建边
        ins(y,x,z);
    }
    memset(boo,false,sizeof(boo));//没有加入最小生成树
    boo[1]=true;//结点1加入最小生成树;从结点1开始生成最小生成树;
    for (int u=head[1];u;u=edge[u].next) que.push(edge[u]);//将和1相连的边入队
    for (int i=1;i<n;i++)    //总共有n-1条边
    {
        Edge temp;
        temp=que.top();//取出距离1结点长度最小的边
        for (;boo[temp.y];que.pop(),temp=que.top());//当这个边的终点已经加入最小生成树,就删除这条边,取次小的边
        que.pop();//删除这条边 已经加入最小生成树 留着也没用
        ans+=temp.z;//加上这条边的权值
        boo[temp.y]=true;//这条边的终点加入最小生成树 temp是一个结构体
        for (int u=head[temp.y];u;u=edge[u].next)//扫一遍和现在的点相连的边
         if (!boo[edge[u].y]) que.push(edge[u]);//将没有在最小生成树中的边入队;
    }
    printf("%d\n",ans);
    return 0;
 }

prim队列优化

(2)kruskal 贪心 并查集

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
int n,m,x,y,z,far[maxn],ans;
const int oo=1234567
struct Edge
{
    int x,y,z;
     Edge(int x=0,int y=0,int z=oo):
      x(x),y(y),z(z) {}
}edge[maxn];
bool cmp(Edge a,Edge b)
{
    return a.z<b.z;
 }
int f(int x)
{
    return far[x]==x?x:far[x]=f(far[x]);
}
void unionn(int x,int y)
{
    far[f(x)]=f(y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        edge[i]=Edge(x,y,z);//这样对结构体赋值要在结构体里写个Edge(int ------)
    }
    sort(edge+1,edge+m+1,cmp);
    for(int i=1;i<=n;i++)
    {
        far[i]=i;
    }
    for(int i=1;i<=m;i++)
    {
        int p=edge[i].x,q=edge[i].y;
        if(f(p)!=f(q)){
            unionn(p,q);
            ans+=edge[i].z;
        }
    }
    printf("%d",ans);
    return 0;
}

kruskal

3、最小瓶颈生成树

最小瓶颈生成树为使所有的生成树中最大权值最小

最小生成树一定是最小瓶颈生成树

最小瓶颈生成树不一定是最小生成树

4、最优比率生成树

二分思想

改日再添

5、最短路径

(1)dijkstra

#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
const int maxm=100000+15;
struct Edge
{
    int x,y,z,next;
    Edge(int x=0,int y=0,int z=0,int next=0):x(x),y(y),z(z),next(next) {}
}edge[maxm*2];
const bool operator < (const Edge &a,const Edge &b)
{
    return a.z>b.z;
 }
int n,m;
int sumedge,head[maxn];
int ins(int x,int y,int z)
{
    edge[++sumedge]=Edge(x,y,z,head[x]);
    return head[x]=sumedge;
}
priority_queue <Edge> que;
int ans;
bool boo[maxn];
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);
        ins(x,y,z);
        ins(y,x,z);
    }
    memset(boo,false,sizeof(boo));
    boo[1]=true;
    for (int u=head[1];u;u=edge[u].next)
      que.push(edge[u]);
    for (int i=1;i<n;i++)    //总共有n-1条边
    {
        Edge temp;
        temp=que.top();
        for (;boo[temp.y];que.pop(),temp=que.top());
        que.pop();
        ans+=temp.z;
        boo[temp.y]=true;
        for (int u=head[temp.y];u;u=edge[u].next)
         if (!boo[edge[u].y]) que.push(edge[u]);
    }
    printf("%d\n",ans);
    return 0;
 } 

dijkstra

(2)bellman-ford

#include <bits/stdc++.h>
using namespace std;

const int maxn=1000;
const int maxm=10000;
const int oo=100000000;
int n,m,x[maxm],y[maxm],z[maxm];
int dis[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x[i],&y[i],&z[i]);
    }
    for (int i=2;i<=n;i++) dis[i]=oo;
    for (int i=1;i<n;i++)
     for (int j=1;j<=m;j++)
      if (dis[x[j]]!=oo && dis[y[j]]>dis[x[j]]+z[j])
       dis[y[j]]=dis[x[j]]+z[j];
    for (int j=1;j<=m;j++)
     if (dis[x[j]]!=oo && dis[y[j]]>dis[x[j]]+z[j])
      {
            printf("-1\n");
            return 0;
            }
    for (int i=1;i<=n;i++)
         printf("%d ",dis[i]);
    printf("\n");
    return 0;
 } 

bellman-ford

(3)floyed

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,z;
const int oo=123456,maxn=1234;
int dis[maxn][maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
        {
            dis[i][j]=oo*(i!=j);//当i和j相等时dis[i][j]赋值为0;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        dis[x][y]=min(dis[x][y],z);
    }
    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]);
    return 0;
}

floyed

6、有向无环图的拓扑排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):x(x),y(y),next(next){}
}edge[maxn];
int head[maxn],sumedge,inn[maxn],que[maxn],Head=1,tail=0;
void add_edge(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}
int n,m,x,y;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add_edge(x,y);
        inn[y]++;
    }
    for(int i=1;i<=n;i++)
    {
        if(inn[i]==0)
        que[++tail]=i;
    }
    for(;Head<=tail;Head++)
    {
        int x=que[Head];
        for(int u=head[x];u;u=edge[u].next)
        {
            inn[edge[u].y]--;
            if(inn[edge[u].y]==0)
            que[++tail]=edge[u].y;
        }
    }
    for(int i=1;i<=tail;i++)
    printf("%d ",que[i]);
    return 0;
}

拓扑排序

7、tarjian求强连通分量

//tarjian
#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):
        x(x),y(y),next(next) {}
}edge[maxn];
int sumedge,head[maxn];
int n,m;
int ins(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    return head[x]=sumedge;
}
bool instack[maxn];
int top,Stack[maxn];
int dfn[maxn],low[maxn],tim;
bool vis[maxn];
int col[maxn],sumcol;
int dfs(int now)
{
    dfn[now]=low[now]=++tim;
    Stack[++top]=now;
    vis[now]=true;//入栈并且访问过
    instack[now]=true;
    for (int u=head[now];u;u=edge[u].next)
     if (instack[edge[u].y])//如果在栈中 说明往回找边了
      low[now]=min(low[now],dfn[edge[u].y]);//low和dfn求最小值 因为已经在栈中 就不是 now结点子树的结点 就要 low和dfn求最小值
     else
     if (!vis[edge[u].y])
     {
         dfs(edge[u].y);
         low[now]=min(low[now],low[edge[u].y]);
     }
     else//应经vis过并且不在栈中的 已经给它找到了连通图 不做处理
     {
     }
    if (low[now]==dfn[now])
    {
        sumcol++;
        col[now]=sumcol;
        while (Stack[top]!=now)
        {
            col[Stack[top]]=sumcol;//将一个连通图上染上一样的颜色
            instack[Stack[top]]=false;
            top--;
        }
        instack[now]=false;
        top--;
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
    }
    for (int i=1;i<=n;i++)
     if (!vis[i]) dfs(i);
    return 0;
}

tarjian

8、tarjian缩点

//缩点
#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):
        x(x),y(y),next(next) {}
}edge[maxn],edge2[maxn];
map <int, bool > Map[maxn];
int sumedge,head[maxn];
int n,m;
int sumedge2,head2[maxn];
int ins2(int x,int y)
{
    edge2[++sumedge2]=Edge(x,y,head2[x]);
    return head2[x]=sumedge;
}
int ins(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    return head[x]=sumedge;
}
bool instack[maxn];
int top,Stack[maxn];
int dfn[maxn],low[maxn],tim;
bool vis[maxn];
int col[maxn],sumcol;
int dfs(int now)
{
    dfn[now]=low[now]=++tim;
    Stack[++top]=now;
    vis[now]=true;
    instack[now]=true;
    for (int u=head[now];u;u=edge[u].next)
     if (instack[edge[u].y])
      low[now]=min(low[now],dfn[edge[u].y]);
     else
     if (!vis[edge[u].y])
     {
         dfs(edge[u].y);
         low[now]=min(low[now],low[edge[u].y]);
     }
     else
     {
     }
    if (low[now]==dfn[now])
    {
        sumcol++;
        col[now]=sumcol;
        while (Stack[top]!=now)
        {
            col[Stack[top]]=sumcol;
            instack[Stack[top]]=false;
            top--;
        }
        instack[now]=false;
        top--;
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
    }
    for (int i=1;i<=n;i++)
     if (!vis[i]) dfs(i);
    for (int i=1;i<=n;i++)
     for (int u=head[i];u;u=edge[u].next)
      if (col[i]!=col[edge[u].y])
       if (Map[col[i]].find(col[edge[u].y])==Map[col[i]].end())
       //相当于 if(map[col[i]][col[edge[u].y]==false)如果这两个不在同一个强连通分量的点没有连起来 为了防止重复加边 所以加一个判断条件
       //如果map[][] 点很多时开的太大 所以用Map[].find ,map<int,bool>Map[maxn]可以理解为bool型的Map[][];
       {
           Map[col[i]][col[edge[u].y]]=true;
           ins2(col[i],col[edge[u].y]);
       }
    return 0;

tarjian缩点

9、tarjian求割点 割边

#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):
        x(x),y(y),next(next) {}
}edge[maxn*2];
int sumedge,head[maxn],n,m;
int ins(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    return head[x]=sumedge;
}
int low[maxn],dfn[maxn],tim;
bool vis[maxn];
bool cutedge[maxn],cutpoint[maxn];
int dfs(int now,int pre)  //需要多记录父边的编号
{
    dfn[now]=low[now]=++tim;
    vis[now]=true;
    int sum=0; //树边数目
    bool boo=false;
    for (int u=head[now];u;u=edge[u].next)
    if ((u^1)!=pre)  //确定不是父边
     if (!vis[edge[u].y])
      {
          sum++;
          dfs(edge[u].y,u);
          if (low[edge[u].y]>dfn[now])  //判断割边
          {
              cutedge[u/2]=true;  //u/2为边的实际编号
          }
        if (low[edge[u].y]>=dfn[now])  //判断割点
         boo=true;
          low[now]=min(low[now],low[edge[u].y]);
      }
      else
      {
          low[now]=min(low[now],dfn[edge[u].y]);
      }
    if (pre==-1)  //分情况判断割点
    {
        if (sum>1) cutpoint[now]=true;
    }
    else
    {
        if (boo) cutpoint[now]=true;
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    sumedge=-1;  //使得代表同一条边的两边编号更有关系
    memset(head,-1,sizeof(head));
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
        ins(y,x);
    }
    for (int i=1;i<=n;i++)
     if (!vis[i]) dfs(i,-1);
    return 0;
}

割点 割边

10、二分图

(1)染色

//O (M+N) 点数+边数
#include<bits/stdc++.h>
using namespace std;

const int maxn=10000+15;
struct Edge
{
    int x,y,next;
    Edge(int x=0,int y=0,int next=0):x(x),y(y),next(next){}
}edge[maxn];
int head[maxn],col[maxn],que[maxn],sumedge,x,y,n,m,h,t;
int add_edge(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    return head[x]=sumedge;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add_edge(x,y);
        add_edge(y,x);
    }
    memset(col,-1,sizeof(col));
    que[h=t=1]=1;
    col[1]=0;
    for(;h<=t;h++)
    {
        int x=que[h];
        for(int u=head[x];u;u=edge[u].next)
        if(col[edge[u].y]!=-1)//已经染上色
        {
            if(col[edge[u].y]==col[x])//边的两边染了相同的颜色
            {
                printf("Wrong!\n");
                return 0;
            }
        }
        else
        {
            col[edge[u].y]=col[x]^1;
            que[++t]=edge[u].y;
        }
    }
    return 0;
}

染色

(2)并查集

#include<bits/stdc++.h>
using namespace std;

const int maxn=1000+15;
int far[maxn],n,m,x,y;
int f(int x)
{
    return far[x]==x?x:far[x]=f(far[x]);
 }
 int main()
 {
     scanf("%d%d",&n,&m);
     for(int i=1;i<=m;i++)
     {
         scanf("%d%d",&x,&y);
         int fx1=f(x*2),fy1=f(y*2-1);//一个染黑一个染白
         far[fx1]=fy1;
         int fx2=f(x*2-1),fy2=f(y*2);//一个染白一个染黑
         far[fx2]=fy2;
     }
     for(int i=1;i<=n;i++)
     {
         if(f(i*2)==f(i*2-1)) //如果这个点既染黑又染白
         {
             printf("Wrong!");
             return 0;
         }
     }
 }

并查集

//呼~终于整理完了
//这个学长好温柔啊QWQ

时间: 2024-12-28 01:50:49

4.29--4.30 图论的相关文章

SICP 1.29 1.30

解:代码如下 (define (sum term a next b)   (if (> a b)       0       (+ (term a) (sum term (next a) next b)))) (define (add-1 x)   (+ x 1)) (define (sum-iter term a next b)   (define (iter a result)     (if (> a b)         result         (iter (next a) (+

10.28 rsync工具介绍 - 10.29/10.30 rsync常用选项 - 10.31 rsync通过ssh同步

- 10.28 rsync工具介绍 - 10.29/10.30 rsync常用选项 - 10.31 rsync通过ssh同步 # 10.28 rsync工具介绍 -/A目录 --> /B目录(A目录更新了一个文件,每次更新都需要把A目录拷贝到B目录),如果用cp命令 比较浪费时间,耗费磁盘空间,磁盘压力 读写之类的, -使用rsync -av /etc/passwd /tmp/1.txt -a选项就是包含了好几个选项  ,v 是可视化,可以看到拷贝的过程 ``` [[email protecte

八周二次课(1月30日) 10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync通过ssh同步

八周二次课(1月30日)10.28 rsync工具介绍10.29/10.30 rsync常用选项10.31 rsync通过ssh同步===================================================================================================================================================================rsync命令:是一个远程数据同步工具,可

10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync通

八周二次课 10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync通过ssh同步 10.28 rsync工具介绍 10.29/10.30 rsync常用选项 设置rsync Rsync 进行同步 删除多余文件 排除掉*.txt的文件 参数:-P 参数:-u 10.31 rsync通过ssh同步 原文地址:http://blog.51cto.com/wbyyy/2067136

10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync

10.28 数据备份工具rsyncrsync不仅可以远程同步数据(类似于scp),而且可以本地同步数据(类似于cp),但是与scp和cp的区别在于:如果数据已经存在,不会覆盖以前的数据rsync会先判断数据是否 存在和新数据的差异,只有数据不同时,才会把不同的部分覆盖yum install -y rsync(安装rsync工具) 10.29/10.30 rsync常用选项rsync的常用选项:-a 包含-rtplgoD-r 同步目录的时候也加上(类似于 cp -r)-v 同步的时候显示同步的进程

笔记 10月29,30

#################自动安装系统############ 1.kickstart脚本 为自动应答系统安装过程中一切问题的脚本文件,可实现系统自动安装.在系统安装完毕后会在系统的 anaconda-ks.cfg 这个文件就是以此系统为模板生成的kickstart脚本 2.手动编辑kickstart脚本的那么度很大 可用系统中system-config-kickstart工具以图形方式制作kickstart yum install system-config-kickstart -y

关于图论的若干巴拉巴拉

最近课堂上正在讲图论 先安利MIT课程:http://open.163.com/special/opencourse/algorithms.html 因为本人对图论的概念并不是很清楚,所以还是整理一下吧. 1.图论的基本概念 几种常见的图的分类: 类型 边 允许多重边 允许环 简单图 无向 否 否 多重图 无向 是 否 伪图 无向 是 是 有向图 有向 否 是 有向多重图 有向 是 是 完全图:n个顶点上的完全图是在每对不同顶点之间都恰有一条边的简单图. 二分图:若把简单图G的顶点集合分为两个不

5.1个人赛解题报告(区间dp,按位与或,图论等水题)

这次5.1打了一场个人赛,已经连赛了三周了,有点疲惫感觉,可能自己太水了,每次都有点小紧张. 这次只解出来三道题,然而有一道按位与按位或的水题不知道思路实在是做题太少,还有就是第一题区间DP,也消耗了不少的时间,但是没有成功的写出来,还是不够熟练啊. 下面写报告 A. System Administrator time limit per test 2 seconds memory limit per test 256 megabytes input standard input output

NetworkX是一个图论与复杂网络建模工具

NetworkX是一个图论与复杂网络建模工具,采用Python语言开发,内置了常用的图与复杂网络分析算法,可以方便的进行复杂网络数据分析.仿真建模等工作.(1)NetworkX支持创建简单无向图.有向图和多重图:(2)内置许多标准的图论算法,节点可为任意数据:(3)支持任意的边值维度,功能丰富,简单易用.https://networkx.github.io/documentation/latest/tutorial.html 以空手道俱乐部数据为例: import matplotlib.pypl