简单图论模板


#define ll long long
#define MT(a,b) memset(a,b,sizeof(a));
const int INF  =  0x3f3f3f3f;
const int ONF  = -0x3f3f3f3f;

1,拓扑排序dfs

int way[N][N],topo[N],vis[N];
int t, n ,m;

bool dfs(int u)
{
    vis[u] = -1;
    for(int v=1;v<=n;v++) if(way[u][v])
    {
        if(vis[v]==-1)            return false;
        else if(!vis[v]&&!dfs(v)) return false;
    }
    vis[u] = 1; topo[t--] = u;
    return true;
}

bool Toposort()
{
    t = n;
    for(int u=1;u<=n;u++) if(!vis[u])
        if(!dfs(u)) return false;
    return true;
}

void init()
{
    memset(way,0,sizeof(way));
    memset(vis,0,sizeof(vis));
    memset(topo,0,sizeof(topo));
}

2,拓扑排序kahn

int n,m;
int way[N][N],cnt[N],topo[N];

void Toposort( )
{
    int l = 0;
    for(int i =1 ;i<=n;i++)
    {
        int u = 0;
        for(int j=1;j<=n; j++) if(!cnt[j])
        {
            u = j;
            break;
        }
        topo[++l] = u; cnt[u]=-1;
        for(int v=1;v<=n;v++) if(way[u][v]) cnt[v]--;
    }
}

void init()
{
    memset(way,0,sizeof(way));
    memset(cnt,0,sizeof(cnt));
    memset(topo,0,sizeof(topo));
}

3,最小生成树prim算法

int way[maxn][maxn];
int vis[maxn],dis[maxn];//dis表示,i点到U集合的最短距离 
int n,m;
int Prim(int start=0)
{

    int ans = 0; MT(vis,0);
    for(int i=0;i<n;i++) dis[i] = (i==start? 0 : INF);
    for(int i=0;i<n;i++)
    {
        int min_edge = INF, k = 0;
        for(int j=0;j<n;j++) if(min_edge>dis[j]&&!vis[j]) min_edge = dis[k=j];
        vis[k] = 1; ans += min_edge;
        for(int j=0;j<n;j++) if(!vis[j]) dis[j] = min(dis[j],way[k][j]);
    }
    return ans ;
}

void init()
{
    for(int i=0;i<n;i++) for(int j=0 ;j<n;j++) way[i][j] = (i==j?0:INF);
}

4,并查集

int f[maxn];//i是f[i]的儿子
int Find(int x){
    return f[x]==x? x : f[x]=Find(f[x]);
}

void Makeset(int n){
    for(int i=0;i<=n;i++) f[i] = i;
}

void Unionset(int x,int y){
    if((x=Find(x))!=(y=Find(y))) f[x] = f[y];
}

5,最小生成树 Kruskal算法

struct edge{
    int u,v,vul;
};
int   f[maxn];
edge  E[maxn];

int Find(int x){
    return f[x]==x? x : f[x]=Find(f[x]);
}

void Makeset(int n){
    for(int i=0;i<=n;i++) f[i] = i;
}

bool Unionset(int x,int y){
    if((x=Find(x))!=(y=Find(y)))
    {
        f[x] = f[y]; return false;
    }
    return true;
}

bool compare(edge a,edge b){
    return a.vul<b.vul;
}

int Kruskal(int n,int m)
{
    Makeset(n); sort(E,E+m,compare);
    int ans = 0;
    for(int i=0;i<m;i++) if(!Unionset(E[i].u,E[i].v)) ans += E[i].vul;
    for(int i=1;i<n;i++) if(Find(i)!=Find(i+1)) return -1;//判断1-n点是否一个父亲节点
    return ans ;
}

6,最短路Floyd算法

int way[maxn][maxn];

void Floyd(int n)
{
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    for(int k=0;k<n;k++)
        way[j][k] = min(way[j][k], way[j][i]+way[i][k]);
}

void init (int n){
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) way[i][j] = (i==j? 0:INF);
}

7,最短路Dijkstra算法O(n^2)

int way[maxn][maxn];
int dis[maxn],vis[maxn];//dis[i]表示起点到i点的最短距离

int Dijkstra(int st,int ed,int n)
{
    for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
    MT(vis,0);
    for(int i=0;i<n;i++)
    {
        int min_way = INF ,k = 0;
        for(int j=0;j<n;j++) if(!vis[j]&&dis[j]<=min_way) min_way = dis[k=j];
        vis[k] = 1;
        for(int j=0;j<n;j++) dis[j] = min(dis[j],dis[k]+way[k][j]);
    }
    return dis[ed];
}

void init(int n){
    for(int i=0;i<n;i++)for(int j=0;j<n;j++) way[i][j] = (i==j? 0:INF);
}

8,最短路Bellman算法O(nm)

struct edge{
    int u,v,vul;
};
int dis[maxn];
edge E[maxn];//若是无向图记得双向加边

int Bellman(int n,int m,int st,int ed)
{
    for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
    for(int i=0;i<n;i++) for(int j=0;j<m;j++)
    {
        int u = E[j].u, v = E[j].v, vul = E[j].vul;
        if(dis[u]<INF) dis[v] = min(dis[v],dis[u]+vul);
    }
    return dis[ed];
}

9,最短路spfa算法(Bellman优化)

struct edge{
    int to,vul;
};
int dis[maxn];
vector<edge>E[maxn];

int Spfa(int n,int st,int ed)
{
    int inq[maxn];MT(inq,0);
    int cnt[maxn];MT(cnt,0);
    for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
    queue<int>Q; Q.push(st); inq[st] = 1;
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for(int i=0;i<E[u].size();i++)
        {
            int v   = E[u][i].to;
            int vul = E[u][i].vul;
            if(dis[u]<INF&&dis[v]>dis[u]+vul)
            {
                dis[v] = dis[u] + vul;
                if(!inq[v]) Q.push(v);
                inq[v] = 1;
                if(++cnt[v]>n) return -1; //存在负环,返回-1
            }
        }
    }
    return dis[ed];
}

void init(int n){
    for(int i=0;i<n;i++) E[i].clear();
}

10,二分图bfs染色判断(无向图)

int way[maxn][maxn];

bool Dye(int n)
{
    int vis[maxn]; MT(vis,0);
    int col[maxn]; MT(col,0);
    for(int i=0;i<n;i++) if(!vis[i])
    {

        queue<int>Q;  Q.push(i);
        vis[i] = 1;   col[i] = 1;
        while(!Q.empty())
        {
            int u = Q.front() ; Q.pop();
            for(int v=0;v<n;v++)
            {
                if(way[u][v]+way[v][u]!=2) continue;//若是单向视为无边(依情况而定)
                if(!vis[v])
                {
                    col[v] = !col[u]; vis[v] = 1;
                    Q.push(v);
                }
                else if(col[u]==col[v]) return false;
            }
        }
    }
    return true;
}

void init(int n){
    MT(way,0);
}

11,二分匹配匈牙利算法

int Lx[maxn],Ly[maxn];
int vis[maxn],way[maxn][maxn];
int n,m;

int dfs(int u)
{
    for(int v = 1;v <= m; v++) if(way[u][v]&&!vis[v])
    {
        vis[v] = 1;
        if(Ly[v]==-1||dfs(Ly[v]))
        {
            Lx[u] = v; Ly[v] = u;
            return 1;
        }
    }
    return 0;
}

int Match()
{

    int ans = 0;
    for(int i=1;i<=n;i++) if(Lx[i]==-1)
    {
        MT(vis , 0);
        ans += dfs(i);
    }
    return ans ;
}

void init()
{
    MT(vis,0); MT(way,0);
    MT(Lx,-1); MT(Ly,-1);

}

12,二分匹配KM算法O(n^3)如果只想求最大权值匹配而不要求是完美匹配的话,把各个不相连的边的权值设置为0。 

#define MT(a,b) memset(a,b,sizeof(a));
const int INF  =  0x3f3f3f3f;
const int ONF  = -0x3f3f3f3f;
const int maxn =  1e3+5;

int way[maxn][maxn];
int Lx[maxn],Ly[maxn],slack[maxn];  //x,y的顶标和松弛量
int couple[maxn],S[maxn],T[maxn];   //组合匹配,S,T集合
int n,m,k;                          //x,y点的个数,组合数

bool match(int u)
{
    S[u] = true;
    for(int v=0;v<m;v++) 
    {
        if(Lx[u] + Ly[v] == way[u][v] && !T[v])
        {
            T[v] = true;
            if(couple[v]==-1||match(couple[v]))
            {
                couple[v] = u;
                return true;
            }
        }
        else slack[v] = min(slack[v],Lx[u] + Ly[v] - way[u][v] );
    }
    return false;
}

void update()
{
    int a = INF;
    for(int i=0;i<m;i++) if(!T[i]) a = min(a,slack[i]);
    for(int i=0;i<n;i++) if(S[i])  Lx[i] -= a;
    for(int i=0;i<m;i++) if(T[i])  Ly[i] += a; else slack[i] -= a;
}

int KM()
{
    MT(Lx,0);MT(Ly,0);MT(couple,-1);
    for(int i=0;i<n;i++) for(int j=0;j<m;j++) Lx[i]=max(Lx[i],way[i][j]);
    for(int i=0;i<n;i++)
    {
        for(int i=0;i<m;i++) slack[i] = INF;
        while(1)
        {
            MT(S,0) ;     MT(T,0);
            if(match(i))  break;
            else          update();
        }
    }

    int ans = 0,cnt = 0;
    for(int i=0;i<m;i++) if(couple[i]!=-1&&way[couple[i]][i]!=ONF)
    {
        ans += way[couple[i]][i];
        cnt ++;
    }
    return cnt == n? ans : -1;
}

void init()
{
    MT(Lx,0);MT(Ly,0);MT(couple,-1);
    for(int i=0;i<n;i++) for(int j=0;j<m;j++) way[i][j] = ONF;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值