模板——图论
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;
}
以上是关于模板——图论的主要内容,如果未能解决你的问题,请参考以下文章