图论
1.建图
1.邻接矩阵
(例:map[i][j]——————表示编号为i的点与编号为j的点有边。)
2.邻接表 (未学);
3.边集数组 (最常用)
代码
struct node
{
int a,b,nx,c;
}t[100010];
int head[100010],n,nz;
void Build edge()
{
int a,b,c;
for(int i=1;i<=n;i++)
{
t[++nz].a=a;
t[nz].b=b;
t[nz].c=c;
t[nz].nx=head[a];
head[a]=nz;
}
}
2.最短路径算法
1.单源最短路径
1.Dijkstra
代码
1.邻接矩阵
void dijkstra(int s)
{
int i,j,Min,p;
for(i=1;i<=n;i++)d[i]=inf;
d[s]=0;v[s]=true;
for(j=1;j<=n;j++)
{
Min=inf;
for(i=1;i<=n;i++)
if((!v[i])&&(d[i]<Min)){Min=d[i];p=i;}
v[p]=true;
for(i=1;i<=n;i++)
if(a[p][i]!=0&&d[i]>d[p]+a[p][i])
d[i]=a[p][i];
}
}
2.边集数组
void dijkstra(int s)
{
int i,j,k,Min,v;
memset(vis,false sizeof(vis));
for(i=0;i<=n;i++)h[i]=inf;
h[s]=0;
for(i=1;i<=n;i++)
{
Min=inf;k=-1;
for(j=1;j<=n;j++)
if((vis[j]==false)&&(Min>h[j]))
{
Min=h[j];
k=j;
}
if(k==-1)break;
vis[k]=true;
j=head[k];
while(j!=-1)
{
v=t[i].v;
if(h[v]>h[k]+t[i].c)h[v]=h[k]+t[i].c;
j=t[i].nx;
}
}
}
2.spfa(可判断负环)
int spfa(int src,int n)
{
int i;
for(i=1;i<=n;i++)
{
vis[i]=0;
dis[i]=inf;
}
dis[src]=0;
int q[110],l=1,r=1;
q[src]=src;
vis[src]=true;
while(l<=r)
{
int u,v;
u=Q[l];
vis[u]=false;
for(i=head[u];i>=0;i=t[i].nx)
{
v=t[i].y;
if(dis[u]+t[i].c<dis[v])
{
dis[v]=dis[u]+t[i].c;
if(if(!vis[v]))
{
r++;
q[r]=v;
vis[v]=true;
}
}
}
r++;
}
return dis[n];
}
2.多源最短路径
1.floyd
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(it j=1;j<=n;j++)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j]
}
3.图的联通性问题
1.无向图的最小环问题(floyd)
代码
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m,g[1001][1001],dis[1001][1001];
int floyd()
{
int Mnin=999999999ll;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
Mnin=min(Mnin,g[i][k]+g[j][k]+dis[i][j]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
dis[j][i]=dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
return Mnin;
}
int main()
{
cin>>n>>m;
int a,b,c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)g[i][j]=dis[i][j]=0;
else g[i][j]=dis[i][j]=999999999ll;
for(int i=1;i<=m;i++)
{
cin>>a>>b>>c;
g[a][b]=g[b][a]=dis[a][b]=dis[b][a]=c;
}
int v=floyd();
if(v==999999999ll)cout<<"impossible"<<endl;
else cout<<v<<endl;
return 0;
}
2.欧拉回路
1.判断
1.对于无向图:
存在欧拉回路的条件:每个点的度都为偶数;
存在欧拉路的条件:有且只有两个点的度为一,且这两个点分别为起点和终点
2.对于有向图:
存在欧拉回路的条件:每个点出度等于入度;
存在欧拉路的条件:存在一个点出度比入度多一作为起点,存在一点入度比出度多一作为终点,其余点出度等于入度;
2.dfs搜索;
在搜素的过程中,记录搜索次序;
3.(Fleury)佛罗莱算法
见博文(Fleury)佛罗莱算法;
4.并查集
代码
int find(int x)
{
if(f[x]==x)return f[x];
return f[x]=find(f[x]);
}
void together(int a,int b)
{
int aa=find(a),bb=find(b);
f[aa]=f[bb];
}
5.最小生成树
1.prim算法
说明
建立一棵树,每次加上这棵树的最近相邻接点,然后更新与新的树相邻的节点的距离,直到顶点都加入了树(可用优先队列优化);
代码
void prim()
{
memset(l,0x7ffff,sizeof(l));
memset(vis,0,sizeof(vis));
l[1]=0;
for(int i=1;i<=n;i++)
{
int k=1;
for(int j=1;j<=n;j++)
if(!vis[j]&&l[k]>l[j])k=j;
vis[k]=true;
for(j=1;j<=n;j++)
if(g[k][j]<l[j])l[j]=g[k][j];//g[k][j]---邻接矩阵;
}
int ans=0;
for(int i=1;i<=n;i++)ans+=l[i];
cout<<ans<<endl;
}
kruskal
1.把图中的边权值按从小到大的顺序排序;
2.加上最短的边(边的两节点未连接,否则考虑下一条边【用并查集判断】);
3.一共添加(n-1)条边;
代码
int find(int x)
{
if(f[x]==x)return f[x];
return f[x]=find(f[x]);
}
void kruskal()
{
sort(t+1,t+n+1);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)
while(l<=nz)
{
l++;p=find(t[l].x);q=find(t[l].y);
if(p!=q)
{
Min=Min+t[i].w;
f[p]=q;
break;
}
}
}
6.拓扑排序
将入度为0的点出栈;
代码
struct node
{
int y,nx,w;
}t[1000010];
int q[110110],d[10010],head[10010];
void top()
{
cin>>n>>p;
int a,b,c,nz=0;
for(int i=1;i<=p;i++)
{
cin>>a>>b>>c;
t[++nz].y=b;t[nz].w=c;t[nz].nx=head[a];head[a]=nz;
d[b]++;
}
int l=1,r=0;
for(int i=1;i<=n;i++)
if(d[i]==0){r++;q[r]=i;}
while(l<=r)
{
int u=q[l];
for(int i=head[u];i;i=t[i].nx)
{
int v=t[v].y;
d[v]--;
if(d[i]==0)
{
r++;q[r]=v;
}
}
l++;
}
}
7.二分图(此处浅谈)
1.二分图的染色
核心思想:将一个图按照一定原则,进行黑白染色,若冲突,则不是二分图;
原则例子1:(双栈排序)若a[i],a[j],a[k]满足i<j<k,且a[i]>a[k]而且a[i]<a[j],则a[j]进入第二个栈;
2.二分图的最大匹配(匈牙利算法);
代码
bool dfs(int p)
{
for(int i=1;1<=n;i++)
{
if(Map[p][i]&&(!chk[i]))
{
chk[i]=true;
if((match[i]==0)||dfs(match[i]))
{
match[i]=p;return true;
}
}
}
return false;
}
void Hungary(int n)
{
int ans=0;
for(int i=1;i=n;i++)
{
memset(chk,0,sizeof(chk));
if(dfs(i))ans++;
}
cout<<ans<<endl;
}