1.邻接表
//定义邻接表
struct edge {int to,Next,v;}e[Maxm];
int h[Maxn];
//建边
void Addedge(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].Next=h[x];
e[cnt].v=z;
h[x]=cnt;
}
//遍历
for(int i=h[x];i;i=e[i].Next)
{
int y=e[i].to
......
}
2.拓扑排序
(1)邻接矩阵法
bool tpsort()
{
for(int i=1;i<=n;i++)
{
int j=1;
while(j<=n&&rd[j]) j++; //找入度为0的点
if(j>n) return 0; //没找到则不存在拓扑序列
ans[++ans[0]]=j; //加入序列
rd[j]=-1; //使其入度不再为0(相当于打一个标记)
for(int k=1;k<=n;k++) if(e[j][k]) rd[k]--; //断边
}
return 1;
}
(2)邻接表法
bool topsort()
{
int top=0;
for(int i=1;i<=n;i++)
if(rd[i]==0) ans[++ans[0]]=i; //将入度为0的点加入序列
while(top<ans[0])
{
int j=ans[++top]; //选取当前入度为0的点
for(int i=h[x];i;i=e[i].Next)
{
int y=e[i].to;
rd[y]--;
if(rd[y]==0) ans[++ans[0]]=y; //如果入度为0则加入序列
}
}
if(top==n) return 1;
return 0;
}
(3)邻接表+堆
bool topsort()
{
priority_queue<int,vector<int>,greater<int> >pq;
for(int i=1;i<=n;i++) if(rd[i]==0) pq.push(i);
while(!pq.empty())
{
int x=pq.top(); pq.pop(); //小根堆维护
ans[++ans[0]]=x;
for(int i=h[x];i;i=e[i].Next)
{
int y=e[i].to;
rd[y]--;
if(rd[y]==0) pq.push(y);
}
}
if(ans[0]==n) return 1;
return 0;
}
3.最小生成树
(1)Prim算法
int prim(int x)
{
int ans=0;
for(int i=1;i<=n;i++) d[i]=INF;
d[x]=0;
for(int i=1;i<=n;i++)
{
int minn=INF,k;
for(int j=1;j<=n;j++)
if(!flag[j] && minn>d[j]) {minn=d[j]; k=j;}
flag[k]=1;
ans+=d[k];
for(int j=1;j<=n;j++)
if(!flag[j] && d[j]>e[k][j]) d[j]=e[k][j];
}
return ans;
}
(2)Kruskal
struct edge {int y,v,w}a[Maxm];
//排序的时候就可以按照a[i].w来排
void kruskal()
{
int k=0;
for(int i=1;i<=m;i++)
{
int f1=getfather(a[i].u);
int f2=getfather(a[i].v);
if(f1==f2) continue;
ans+=a[i].w;
f[f1]=f2;
k++;
if(k>n) break;
}
}
4.最短路径
(1)Dijkstra算法
int dijkstra(int s,int t)
{
for(int i=1;i<=n;i++) d[i]=INF;
d[s]=0;
for(int i=1;i<=n;i++)
{
int minn=INF,k;
for(int j=1;j<=n;j++)
if(!flag[j] && minn>d[j]){minn=d[j]; k=j;}
flag[k]=1;
for(int j=1;j<=n;j++)
if(e[k][j]&&!flag[j]&&d[k]+e[k][j]<d[j])
d[j]=d[k]+e[k][j];
}
return d[t];
}
(2)Floyd算法
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(e[i][k]!=INF&&e[k][j]!=INF&&e[i][k]+e[k][j]<e[i][j])
e[i][j]=e[i][k]+e[k][j];
}
(3)SPFA算法
int spfa(int s,int t)
{
queue<int>q;
for(int i=1;i<=n;i++) d[i]=INF;
d[s]=0; q.push(s);
while(!q.empty())
{
int x=q.front(); q.pop();
flag[x]=0;
for(int i=h[x];i;i=e[i].Next)
{
int y=e[i].to;
if(d[y]>d[x]+e[i].v)
{
d[y]=d[x]+e[i].v;
if(!flag[y]) {flag[y]=1; q.push(y);}
}
}
}
return d[t];
}
5.图的连通性
5.1强联通分量
(1)Tarjan算法
void tarjan(int x)
{
dfn[x]=low[x]=++sign;
s[++top]=x;
flag[x]=1;
for(int i=1;i<=n;i++)
if(e[x][i])
{
if(dfn[i]==0)
{
tarjan(i);
low[x]=min(low[x],low[i]);
}
else if(flag[i]) low[x]=min(low[x],dfn[i]);
}
if(low[x]==dfn[x])
{
num++;
int y;
do
{
y=s[top--];
flag[y]=0;
}
while(y!=x);
}
}
(2)缩点
//加belong数组(记录y点属于哪个强联通分量)
if(low[x]==dfn[x])
{
num++;
int y;
do
{
y=s[top--];
flag[y]=0;
belong[y]=num;
}
while(y!=x);
}
//计算缩点后的入度出度
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(e[j][i]&&belong[i]!=belong[j]) rd[belong[i]]++;
if(e[i][j]&&belong[i]!=belong[j]) cd[belong[i]]++;
}
5.2割点
(1)Tarjan算法
void dfs(int x)
{
dfn[x]=low[x]=++sign;
for(int i=1;i<=n;i++)
if(e[x][i]&&prt[x]!=i)
{
if(dfn[i]==0)
{
prt[i]=x;
dfs(i);
low[x]=min(low[x],low[i]);
if(low[i]>=dfn[x])
{
if(x==1) // 特判起点节点的情况
{
son++;
if(son==2) ans++;
}
else ans++;
}
}
else low[x]=min(low[x],dfn[i]);
}
}
5.3割边
void dfs(int x)
{
dfn[x]=low[x]=++sign;
for(int i=1;i<=n;i++)
if(e[x][i]&&prt[x]!=i)
{
if(dfn[i]==0)
{
prt[i]=x;
dfs(i);
low[x]=min(low[x],low[i]);
if(low[i]>dfn[x]) ans++;
}
else low[x]=min(low[x],dfn[i]);
}
}