今天主要学习了最小生成树和二分图初步
1.最小生成树
1)prime算法
从某个起点s开始,不断地在未标记的点中,取与已标记的点(已加入生成树的点)所连的边权值最小的点,将这个点标记并加入最小生成树中。
重复直到所有的顶点都被加入到最小生成树中为止。
实现步骤:
vis[]标记节点,Map[][]存图
dis[i]表示节点i到已标记的点的集合的最短距离
(1)初始化:在起点处标记,dis[]设成到起点的距离
(2)循环n-1次,每次找到未标记的dis[]最小的节点,将其添加到生成树中并标记。然后对尚未标记的点尝试更新dis[]。
int prim(int s)
{
int res=0;
memset(vis,0,sizeof(vis));
for(int i=1;idis[j])
minn=dis[j],pos=j;
vis[pos]=1;
res+=minn;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dis[pos][j])
dis[j]=w[pos][j];
}
}
return res;
}
2)kruskal算法
连通分支:可以看作是图中一整块独立且连通的点和边
将所有的边按照权值由小到大排序,依次遍历每一条边。如果边的两端点不属于同一集合,那么就将这两个点合并到同一集合,直到所有的点都属于同一集合。这时所有的点和合并了端点的边组成了这个最小生成树。(不断地合并能构成最小生成树的连通分支)
合并操作:并查集实现
int maxn;
int pre[105];
struct node
{
int from;
int to;
int w;
}e[maxn];
bool cmp(node a,node b)
{
return a.w
2.二分图
匹配:对于二分图G=
最大匹配:所含边数最多的匹配
完全匹配:每个顶点都和匹配中的某条边相关联。
增广路径: 设M为二分图G已匹配边的集合,若P是图G中一条连通两个未匹配顶点的路径(P的起点终点在不同两侧)
并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
1)最大匹配的匈牙利算法
基本思想:不断寻找增广路以增大匹配数
(1)初始时将匹配的边集M置为空
(2)找出一条增广路P,对P上的边取反获得更大的M’来代替M
(3)重复步骤(2)直至找不到新的增广路
int hungary()
{
int ans=0; //-1表示初始时没有点被匹配
memset(link,-1,sizeof(link));
for(int i=1;i<=nx;i++) //遍历X部的每一个点
{
if(link[i]==-1) //如果尚未被匹配
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++; //尝试寻找增广路
}
}
return ans;
}
bool dfs(int u)
{//遍历Y部的每一个点
for(int i=1;i<=ny;i++)
{//找一个和u有边相连并且还没有访问的点
if(map[u][i]&&!vis[i])
{
vis[i]=1;
if(link[i]==-1||dfs(link[i]))
{//如果这个点尚未匹配
//或者已经匹配且从匹配点出发能在寻找一条增广路
link[u]=i;
return ture; //u和i匹配成功
}
}
}
return false; //没有增广路
}
点覆盖:选取顶点集V的一个子集S,使得图中每条边都至少有一个端点在S中。
二分图最小点覆盖=最大匹配数
独立集:选取顶点集V的一个子集S,使得S中任意两个点之间都没有路径。
边覆盖:选取边集E的一个子集P,使得图中每一个顶点都是P中某条边的一个端点。
二分图最大独立集=最小边覆盖=顶点总数目-最小点覆盖
即顶点总数目-最大匹配数