1.图的遍历
图的bfs
-需要用到队列来保存节点信息
图的dfs
-递归版dfs可能爆栈,尽量使用手写栈或手动扩大栈容量
2.图的联通性
并查集维护不存在删边操作的动态图连通性
-在部分存在删边操作的情况下可以离线处理变成倒序加边
Tarjan算法求出无向图的割点和有向图的强连通分量
-利用时间戳的和dfs树的特性在 O(n) 时间求出
3.最短路问题
队列优化的Bellman-Ford算法
-代码简洁,可以处理负权环,但复杂度不靠谱,可能被卡
堆优化的Dijkstra算法
-速度快,在用stl的优先队列的情况下代码可以同样简洁
基于dfs的spfa算法
-在处理部分费用流问题时速度奇快无比,例如二分图
求全源最短路的Floyd算法
-代码四行,灵活,可求出最小环
4.网络流
Dinic算法
-大力出奇迹,绝大多数情况下没有超时,很难卡
费用流
-基于spfa的费用流
-zkw费用流
有上下界的网络流
-只需在原模型上稍作更改即可
最小割模型
-可以解决很多优化问题
5.二分图
二分图最大匹配
-匈牙利算法:常数小
-使用网络流求解
二分图最大权匹配
-KM算法,复杂度
O(n3)
(可惜我不会)
-也可以使用最大费用最大流的方法求解,需要引入一个新的节点
6.拓扑排序
基于dfs的拓扑排序算法
-只需在访问完一个节点的所有后继后将当前点加入即可
7.差分约束系统
模型转换,用最短/长路算法解决
8.2-SAT问题
也可以用图论模型解决
9.最小生成树
Kruskal算法
-基于贪心的最小生成树算法,同样可以解决最大生成树
10.01分数规划问题
求最小平均权值环
-二分答案,每次重新建图,用dfs版的spfa判负环即可
下面是部分算法的代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int inf=0x3f3f3f3f;
int getint()
{
int f=1,g=0;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9')g=(g<<3)+(g<<1)+c-'0',c=getchar();
return f*g;
}
const int maxn=10005;
namespace Tarjan_One{//find the Cut_Vertex
vector<int> g[maxn];
void addedge(int from,int to)
{
g[from].push_back(to);
g[to].push_back(from);
}
int dfn[maxn];
int low[maxn];
bool cut[maxn];
int Index;
int n,m;
void read()
{
n=getint();
m=getint();
int x,y;
for(int i=1;i<=m;i++)
{
x=getint();
y=getint();
addedge(x,y);
}
}
void dfs(int x,int fa)
{
dfn[x]=low[x]=++Index;
int child=0;
for(vector<int>::iterator it=g[x].begin();it!=g[x].end();it++)
{
int to=*it;
if(!dfn[to])
{
dfs(to,x);
child++;
low[x]=min(low[x],low[to]);
if(low[to]>=dfn[x])
{
cut[x]=true;
}
}
else if(dfn[to]<dfn[x] && to!=fa)
{
low[x]=min(low[x],dfn[to]);
}
}
if(fa==0 && child==1)
{
cut[x]=false;
}
}
void solve()
{
read();
dfs(1,0);
for(int i=1;i<=n;i++)
{
if(cut[i])
{
printf("%d ",i);
}
}
puts("");
}
}
namespace Tarjan_Two{//find the Strong_Connected_Compartment
vector<int> g[maxn];
void addedge(int from,int to)
{
g[from].push_back(to);
}
int n,m;
int dfn[maxn];
int Index;
int low[maxn];
int q[maxn];
int top;
bool inq[maxn];
int scc;
int belong[maxn];
void dfs(int x)
{
dfn[x]=low[x]=++Index;
q[++top]=x;inq[x]=true;
for(vector<int>::iterator it=g[x].begin();it!=g[x].end();it++)
{
int to=*it;
if(!dfn[to])
{
dfs(to);
low[x]=min(low[x],low[to]);
}
else if(inq[to])
{
low[x]=min(low[x],dfn[to]);
}
}
if(dfn[x]==low[x])
{
int temp=0;scc++;
while(temp!=x)
{
temp=q[top--];
inq[temp]=false;
belong[temp]=scc;
}
}
}
void read()
{
n=getint();
m=getint();
int x,y;
for(int i=1;i<=m;i++)
{
x=getint();
y=getint();
addedge(x,y);
}
}
void solve()
{
read();
for(int i=1;i<=n;i++)
{
if(!dfn[i])dfs(i);
}
for(int i=1;i<=n;i++)
{
printf("%d:%d ",i,belong[i]);
}
puts("");
}
}
namespace Find_Set{//find set
int p[maxn];
int n;
void init(int nn){n=nn;for(int i=0;i<=n;i++)p[i]=i;}
int find(int x){return p[x]==x ? x :p[x]=find(p[x]);}
void uni(int x,int y){p[find(x)]=find(y);}
bool same(int x,int y){return find(x)==find(y);}
}
namespace Network_Flow{//dinic
struct edge{
int from,to,cap;
};
vector<int> g[maxn];
vector<edge> eds;
int n;
int h[maxn];
queue<int> q;
int ans;
void addedge(int from,int to,int cap)
{
g[from].push_back(eds.size());
eds.push_back((edge){from,to,cap});
g[to].push_back(eds.size());
eds.push_back((edge){to,from,0});
}
bool bfs()
{
memset(h,-1,sizeof(h));
q.push(1);
h[1]=0;
int i;
while(!q.empty())
{
int now=q.front();q.pop();
for(i=0;i<g[now].size();i++)
{
edge e=eds[g[now][i]];
if(h[e.to]==-1 &&e.cap)
{
q.push(e.to);
h[e.to]=h[now]+1;
}
}
}
return h[n]!=-1;
}
int dfs(int x,int f)
{
if(x==n)return f;
int use=0;
int w;
for(int i=0;i<g[x].size();i++)
{
edge& e1=eds[g[x][i]];
edge& e2=eds[g[x][i]^1];
if(h[x]+1==h[e1.to])
{
w=f-use;
w=dfs(e1.to,min(e1.cap,w));
e1.cap-=w;
e2.cap+=w;
use+=w;
if(use==f)return f;
}
}
if(!use)h[x]=-1;
return use;
}
void dinic()
{
while(bfs())
{
ans+=dfs(1,inf);
}
}
}
namespace Minimum_Cost_Maximum_Flow{
struct edge{
int from,to,cap,cost;
};
int s,t;
vector<int> g[maxn];
vector<edge> eds;
void addedge(int from,int to,int cap,int cost)
{
g[from].push_back(eds.size());
eds.push_back((edge){from,to,cap,cost});
g[to].push_back(eds.size());
eds.push_back((edge){to,from,0,-cost});
}
int d[maxn];
bool inq[maxn];
queue<int> q;
int pre[maxn];
bool spfa()
{
memset(d,0x3f,sizeof d);
memset(pre,0x3f,sizeof pre);
d[s]=0;
q.push(s);
inq[s]=true;
while(!q.empty())
{
int x=q.front();q.pop();inq[x]=false;
for(int i=0;i<g[x].size;i++)
{
edge e=eds[g[x][i]];
if(d[e.to]>d[x]+e.cost && e.cap)
{
d[e.to]=d[x]+e.cost;
pre[e.to]=g[x][i];
if(!inq[e.to])
{
q.push(e.to);
inq[e.to]=true;
}
}
}
}
return d[t]!=inf;
}
int mcmf()
{
int cost=0;
int flow=0;
while(spfa())
{
int fl=inf;
int co=0;
int p=t;
while(p!=s)
{
fl=min(eds[pre[p]].cap,fl);
co+=eds[pre[p]].cost;
p=eds[pre[p]].from;
}
p=t;
cost+=co*fl;
flow+=fl;
while(p!=s)
{
eds[pre[p]].cap-=fl;
eds[pre[p]^1].cap+=fl;
p=eds[pre[p]].from;
}
}
return cost;
}
}
namespace Minimum_Everage_Weight_Circle{
struct edge{
int from,to;
db len;
};
vector<edge> eds;
vector<int> g[maxn];
int n,m;
db dis[maxn];
bool mark[maxn];
void addedge(int from,int to,db len)
{
g[from].push_back(eds.size());
eds.push_back((edge){from,to,len});
}
bool flag;
db temp;
void spfa(int x)
{
mark[x]=1;
for(int i=0;i<g[x].size();i++)
{
edge e=eds[g[x][i]];
if(dis[x]+e.len<dis[e.to])
{
if(!mark[e.to])
{
dis[e.to]=dis[x]+e.len;
spfa(e.to);
}
else flag=true;
if(flag)return;
}
}
mark[x]=0;
}
bool check(db mid)
{
memset(mark,0,sizeof mark);
memset(dis,0,sizeof dis);
for(int i=0;i<eds.size();i++)
{
eds[i].len-=mid;
}
flag=false;
for(int i=1;i<=n;i++)
{
spfa(i);
if(flag)
{
for(int i=0;i<eds.size();i++)
{
eds[i].len+=mid;
}
return true;
}
}
for(int i=0;i<eds.size();i++)
{
eds[i].len+=mid;
}
return false;
}
}
namespace Hungarian_Algorithm{
vector<int> g[maxn];
int lk[maxn];
bool y[maxn];
int n;
int m;
void addedge(int from,int to)
{
vector[from].push_back(to);
vector[to].push_back(from);
}
bool find(int x)
{
for(vector<int>::iterator it=g[x].begin();it!=g[x].end();it++)
{
int to=*it;
if(!y[to])
{
y[to]=true;
if(!lk[to] || find(lk[to]))
{
lk[to]=x;
lk[x]=to;
return true;
}
}
}
return false;
}
void solve()
{
int cnt=0;
for(int i=1;i<=n;i++)
{
memset(y,false,sizeof y);
if(find(i))cnt++;
}
}
}
namespace Dijkstra{
struct edge{
int to,len;
bool operator < (const edge &e)const
{
return len<e.len;
}
};
vector<edge> g[maxn];
int s,t;
void addedge(int from,int to,int len)
{
g[from].push_back((edge){to,len});
g[to].push_back((edge){from,len});
}
priority_queue<edge> q;
int d[maxn];
void dijkstra()
{
memset(d,0x3f,sizeof d);
d[s]=0;
q.push((node){s,0});
while(!q.empty())
{
edge ed=q.top();q.pop();
int x=ed.to;
if(ed.len>d[x])continue;
for(int i=0;i<g[x].size();i++)
{
edge e=g[x][i];
if(d[e.to]>d[x]+e.len)
{
d[e.to]=d[x]+e.len;
q.push((edge){e.to,d[e.to]});
}
}
}
}
}
int main()
{
return 0;
}