模板——图论

Posted szsz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板——图论相关的知识,希望对你有一定的参考价值。

缩点(强连通分量)

点击查看代码

const int N=1e5+5,inf=1e9;
vector<int> a[N];
stack<int> stk;
bool vis[N],instk[N];
int dfn[N],low[N],col[N],w[N]; // co:染色结果,w:点权
vector<int> sz; // sz:第i个颜色的点数
int n,m,dcnt;//
void dfs(int x) // Tarjan求强联通分量
    vis[x]=instk[x]=1; stk.push(x);
    dfn[x]=low[x]=++dcnt;
    for(auto p:a[x])
        if(!vis[p])dfs(p);
        if(instk[p])low[x]=min(low[x],low[p]);
    
    if(low[x]==dfn[x])
        int t; sz.push_back(0); // 记录
        do
            t=stk.top();
            stk.pop();
            instk[t]=0;
            sz.back()+=w[t]; // 记录
            col[t]=sz.size(); // 染色
        while(t!=x);
    

void getscc()
    fill(vis,vis+n,0);
    sz.clear();
    for(int i=1;i<=n;i++) if(!vis[i])dfs(i);

struct pii
    int u,v;
;
void shrink() // 缩点,在a里重构
    vector<pii> tmp;
    getscc();
    for(int i=1;i<=n;i++) 
        for (auto j: a[i]) if (col[i] != col[j]) 
                pii u = col[i], col[j];
                tmp.push_back(u);
            
    
    n=sz.size();
    for(int i=1;i<=n;i++)
        a[i].clear();
        w[i]=sz[i];
    
    for(auto i:tmp)
        a[i.u].push_back(i.v);
    

最大流+输出方案

点击查看代码

struct FLOW
    struct edgeint to,w,nxt;;
    vector<edge> a; int head[N],cur[N];
    int n,s,t;
    queue<int> q; bool inque[N];
    int dep[N];
    void ae(int x,int y,int w) // add edge
        //cout<<"ae:"<<x<<" "<<y<<" "<<w<<endl;
        a.push_back(y,w,head[x]);
        head[x]=a.size()-1;
    
    bool bfs() // get dep[]
        fill(dep,dep+n,inf); dep[s]=0;
        copy(head,head+n,cur);
        q=queue<int>(); q.push(s);
        while(!q.empty())
            int x=q.front(); q.pop(); inque[x]=0;
            for(int i=head[x];i!=-1;i=a[i].nxt)
                int p=a[i].to;
                if(dep[p]>dep[x]+1 && a[i].w)
                    dep[p]=dep[x]+1;
                    if(inque[p]==0)
                        inque[p]=1;
                        q.push(p);
                    
                
            
        
        return dep[t]!=inf;
    
    int dfs(int x,int flow) // extend
        int now,ans=0;
        if(x==t)return flow;
        for(int &i=cur[x];i!=-1;i=a[i].nxt)
            int p=a[i].to;
            if(a[i].w && dep[p]==dep[x]+1)
                if((now=dfs(p,min(flow,a[i].w))))
                    a[i].w-=now;
                    a[i^1].w+=now;
                    ans+=now,flow-=now;
                    if(flow==0)break;
                
        
        return ans;
    
    bool is[N];
    void init(int _n)
        n=_n+1; a.clear();
        fill(head,head+n,-1);
        fill(inque,inque+n,0);
        fill(is,is+n,0);
    
    int solve(int _s,int _t,int _n) // return max flow
        s=_s,t=_t;
        int ans=0;
        while(bfs()) ans+=dfs(s,inf);
        for(int e=head[s];e>=0;e=a[e].nxt) if(a[e^1].w) is[a[e].to]=1;
        for(int e=head[t];e>=0;e=a[e].nxt) if(a[e].w)
            int v=a[e].to,u=v;
            while(1)
                if(u>=1 && u<=_n && is[u])
                    is[u]=0;
                    break;
                
                int w=0,tmp=0;
                for(int i=head[u];i>=0;i=a[i].nxt) if(i&1 && a[i].w)
                    w=a[i].to;
                    tmp=i;
                    break;
                
                if(!w) break;
                a[tmp].w--;
                u=w;
            
            //cout<<u<<" "<<v-_n<<endl;
           // fa[find(u)]=find(v-_n);
        
        return ans;
    
flow;
void add(int x,int y,int w)flow.ae(x,y,w),flow.ae(y,x,0);

图论模板——最大流及费用流模板

图论模板——最大流及费用流模板

最大流——SAP

时间复杂度:O(v^2*e)

const int MAXN=1010;//点数的最大值
const int MAXM=1010;//边数的最大值
const int INF=0x3f3f3f3f;
struct Node
{
    int from,to,next;
    int cap;
}edge[MAXM];
int tol;
int head[MAXN];
int dep[MAXN];
int gap[MAXN];//gap[x]=y :说明残留网络中dep[i]==x的个数为y
int N;//N是总的点的个数,包括源点和汇点

void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int w)
{
    edge[tol].from=u;
    edge[tol].to=v;
    edge[tol].cap=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].from=v;
    edge[tol].to=u;
    edge[tol].cap=0;
    edge[tol].next=head[v];
    head[v]=tol++;
}

void BFS(int start,int end)
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0]=1;
    int que[MAXN];
    int front,rear;
    front=rear=0;
    dep[end]=0;
    que[rear++]=end;
    while(front!=rear)
    {
        int u=que[front++];
        if(front==MAXN)front=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dep[v]!=-1)continue;
            que[rear++]=v;
            if(rear==MAXN)rear=0;
            dep[v]=dep[u]+1;
            ++gap[dep[v]];
        }
    }
}

int SAP(int start,int end)
{
    int res=0;
    BFS(start,end);
    int cur[MAXN];
    int S[MAXN];
    int top=0;
    memcpy(cur,head,sizeof(head));
    int u=start;
    int i;
    while(dep[start]<N)
    {
        if(u==end)
        {
            int temp=INF;
            int inser;
            for(i=0;i<top;i++)
               if(temp>edge[S[i]].cap)
               {
                   temp=edge[S[i]].cap;
                   inser=i;
               }
            for(i=0;i<top;i++)
            {
                edge[S[i]].cap-=temp;
                edge[S[i]^1].cap+=temp;
            }
            res+=temp;
            top=inser;
            u=edge[S[top]].from;
        }
        if(u!=end&&gap[dep[u]-1]==0)//出现断层,无增广路
          break;
        for(i=cur[u];i!=-1;i=edge[i].next)
           if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
             break;
        if(i!=-1)
        {
            cur[u]=i;
            S[top++]=i;
            u=edge[i].to;
        }
        else
        {
            int min=N;
            for(i=head[u];i!=-1;i=edge[i].next)
            {
                if(edge[i].cap==0)continue;
                if(min>dep[edge[i].to])
                {
                    min=dep[edge[i].to];
                    cur[u]=i;
                }
            }
            --gap[dep[u]];
            dep[u]=min+1;
            ++gap[dep[u]];
            if(u!=start)u=edge[S[--top]].from;
        }
    }
    return res;
}

费用流——SPFA费用流

时间复杂度:O(k * e * A) // A为流量,k在稀疏图中约为2,最高为v

const int MAXN = 1010;
const int MAXM = 1010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow,cost;
}edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1

void init(int n)
{
    N = n;
    tol = 0;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int cap,int cost)
{
    edge[tol].to = v;
    edge[tol].cap = cap;
    edge[tol].cost = cost;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = 0;
    edge[tol].cost = -cost;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}

bool spfa(int s,int t)
{
    queue<int>q;
    for(int i = 0;i < N;i++)
    {
        dis[i] = INF;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1;i = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow &&
               dis[v] > dis[u] + edge[i].cost )
            {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1)return false;
    else return true;
}//返回的是最大流,cost存的是最小费用

int minCostMaxflow(int s,int t,int &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        int Min = INF;
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
        {
            if(Min > edge[i].cap - edge[i].flow)
                Min = edge[i].cap - edge[i].flow;
        }
        for(int i = pre[t];i != -1;i = pre[edge[i^1].to])
        {
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i].cost * Min;
        }
        flow += Min;
    }
    return flow;
}

以上是关于模板——图论的主要内容,如果未能解决你的问题,请参考以下文章

图论模板

图论模板——最大流及费用流模板

图论模板目录

干货系列——模板 之 图论1

模板图论

模板图论