求最小生成树(暴力法,prim,prim的堆优化,kruskal)

5 7
1 2 2
2 5 2
1 3 4
1 4 7
3 4 1
2 3 1
3 5 6

我们采用的是dfs的回溯暴力,所以对于如下图,只能搜索到3条路,就是那种dfs的路。

思路:

暴力求最小生成树
求这个图的最小生成树
我就要看有多少个点被选进去了,vis数组就好,并且用个n来表示已经被选的点的个数
然后记录所以已经选了的路径和

 #include <bits/stdc++.h>
#define INFINITE 0x3fffffff
using namespace std;
struct node{
int v;
int w;
node(int v,int w){
this->v=v;
this->w=w;
}
};
vector<node> vec[];
int edgeNum[];
int n,m;
bool vis[]; int minDis=INFINITE; void addEdge(int u,int v,int w){
edgeNum[u]++;
vec[u].push_back(node(v,w));
} void init(){
cin>>n>>m;
for(int i=;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
} /*
暴力求最小生成树
求这个图的最小生成树
我就要看有多少个点被选进去了,vis数组就好,并且用个n来表示已经被选的点的个数
然后记录所以已经选了的路径和
*/
//记录起点,记录选了个点
void search(int start,int dis,int cur){
//边界一定要清楚
//而且这里是5不是6
if(cur==){//这里写成n==n 第几错误傻逼错误满天飞
cout<<dis<<endl;
if(dis<minDis){
minDis=dis;
}
return ;
}
for(int i=;i<edgeNum[start];i++){ int v=vec[start][i].v;
int w=vec[start][i].w;
//cout<<vis[v]<<endl;
if(!vis[v]){
cout<<start<<" "<<v<<" "<<w<<endl;
vis[v]=true;
search(v,dis+w,cur+);
vis[v]=false;
} }
} int main(){
freopen("in.txt","r",stdin);
init();
vis[]=true;//这句话居然在search下面
search(,,); cout<<minDis<<endl;
return ;
}

上述代码再说几点

1、上述代码并不能解决最小生成树,只能求出DFS的最小生成树情况,所以还需要其它的暴力方法

2、回溯有问题

3、回溯的边界请想清楚

4、变量的初始值请想清楚,dis初始时0不是INFINITE

5、第71行我开始居然写到了72行之下

6、写代码太不专心了,傻逼错误太多了

7、第45行也是

8、暴力搜索的话应该是搜索已经求出来的集合到未求出来的集合的路径,这样可以暴力求出最小生成树

9、树形dp可以求出最小生产树,自然记忆化递归也可以

代码2,把回溯中的变量dis写在了外面,更好理解回溯

 #include <bits/stdc++.h>
#define INFINITE 0x3fffffff
using namespace std;
struct node{
int v;
int w;
node(int v,int w){
this->v=v;
this->w=w;
}
};
vector<node> vec[];
int edgeNum[];
int n,m;
bool vis[];
int dis=;
int minDis=INFINITE; void addEdge(int u,int v,int w){
edgeNum[u]++;
vec[u].push_back(node(v,w));
} void init(){
cin>>n>>m;
for(int i=;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
} /*
暴力求最小生成树
求这个图的最小生成树
我就要看有多少个点被选进去了,vis数组就好,并且用个n来表示已经被选的点的个数
然后记录所以已经选了的路径和
*/
//记录起点,记录选了个点
void search(int start,int cur){
//边界一定要清楚
//而且这里是5不是6
if(cur==){//这里写成n==n 第几错误傻逼错误满天飞
cout<<dis<<endl;
if(dis<minDis){
minDis=dis;
}
return ;
}
for(int i=;i<edgeNum[start];i++){ int v=vec[start][i].v;
int w=vec[start][i].w;
//cout<<vis[v]<<endl;
if(!vis[v]){
cout<<start<<" "<<v<<" "<<w<<endl;
vis[v]=true;
dis+=w;
search(v,cur+);
dis-=w;
vis[v]=false;
} }
} int main(){
freopen("in.txt","r",stdin);
init();
vis[]=true;//这句话居然在search下面
search(,); cout<<minDis<<endl;
return ;
}

prim

 #include <bits/stdc++.h>
#define INFINITE 0x3fffffff
using namespace std;
struct node{
int v;
int w;
node(int v,int w){
this->v=v;
this->w=w;
}
};
vector<node> vct[];
int edgeNum[];
int n,m;
bool vis[];
//集合a到集合b的最短距离
int dis[];
int ans[];
int juli=; void printDis(){
for(int i=;i<=n;i++){
cout<<dis[i]<<" ";
}
cout<<endl;
} void addEdge(int u,int v,int w){
edgeNum[u]++;
vct[u].push_back(node(v,w));
} void init(){
cin>>n>>m;
for(int i=;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
} void prim(int start){
memset(dis,0x3f,sizeof(dis));
vis[start]=true;
dis[start]=;
ans[]=start;
//时间复杂度 e+n^2
for(int i=;i<=n;i++){
//更新
for(int j=;j<edgeNum[start];j++){
int v=vct[start][j].v;//这里的j写成i了
int w=vct[start][j].w;//这里的j写成i了
if(!vis[v]&&w<dis[v]){
dis[v]=w;
}
} //找最小
int minv=INFINITE,min_i;
for(int j=;j<=n;j++){
if(!vis[j]&&dis[j]<minv){//这里的vis写成了dis,这些sb错误真的要爆了我
minv=dis[j];
min_i=j;
}
}
juli+=dis[min_i];
vis[min_i]=true;
ans[i]=min_i;
start=min_i;
}
} void print(){
cout<<juli<<endl;
for(int i=;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<endl;
} int main(){
freopen("in.txt","r",stdin);
init();
prim();
print();
return ;
}

上面代码说几点:

1、总的思路:集合a到集合b的最短距离,并不是新选的点到其它点的距离

2、还是有超级多傻逼错误

3、52,53行: 这里的j写成i了

4、62行,vis写成dis,其它位置的dis写成vis

5、每一轮里面:更新+找最小

6、加强复习,这个最小生成树真的弄了一万遍了

7、在代码中看时间复杂度,时间复杂度 e+n^2

堆优化的prim

 #include <bits/stdc++.h>
#define INFINITE 0x3fffffff
using namespace std;
struct node{
int v;
int w;
node(int v,int w){
this->v=v;
this->w=w;
}
};
vector<node> vct[];
int edgeNum[];
int n,m;
bool vis[];
//集合a到集合b的最短距离
int dis[];
int ans[];
int juli=; void printDis(){
for(int i=;i<=n;i++){
cout<<dis[i]<<" ";
}
cout<<endl;
} void addEdge(int u,int v,int w){
edgeNum[u]++;
vct[u].push_back(node(v,w));
} void init(){
cin>>n>>m;
for(int i=;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
} struct myCmp{
bool operator ()(int a,int b){//忘记写(),之前写了被用了
return dis[a]>dis[b];
}
};
priority_queue<int,vector<int>,myCmp> q;
void prim1(int start){
int cnt=;
memset(dis,0x3f,sizeof(dis));
q.push(start);//这里写成了push_back
dis[start]=;
while(!q.empty()){
int u=q.top();
q.pop();
if(vis[u]) continue;
vis[u]=true;
ans[++cnt]=u;
juli+=dis[u];
for(int i=;i<edgeNum[u];i++){
int v=vct[u][i].v;
int w=vct[u][i].w;
if(!vis[v]&&w<dis[v]){
dis[v]=w;
q.push(v);
}
}
} } void print(){
cout<<juli<<endl;
for(int i=;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<endl;
} int main(){
freopen("in.txt","r",stdin);
init();
prim1();
print();
return ;
}

关于上面代码说几点:

1、因为dijkstra算法可以看成prim算法的特例,因为都是集合到集合的距离,不过dijkstra中的一个集合只有起始元素

2、所以两者算法极其相识,堆优化也是几乎一样

3、傻逼错误还是很多

4、52行的push写成了push_back,因为queue是push,vector是pushback

5、重载()的()写了被用了,所以导致漏掉了

6、时间复杂度:e+nlogn

kruskal

 #include <bits/stdc++.h>
using namespace std;
struct edgeNode{
int u;
int v;
int w;
bool vis;
bool operator <(const edgeNode &p) const{
return w<p.w;
}
}edge[];
//father不是边的father,而是点的father
int fa[];
int n,m;
int juli=; void print(); void init(){
cin>>n>>m;
for(int i=;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
edge[i].u=u;
edge[i].v=v;
edge[i].w=w;
}
} //int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
} void kruskal(){ for(int i=;i<=n;i++) fa[i]=i;
for(int i=;i<=m;i++){
int x=find(edge[i].u);
int y=find(edge[i].v);
if(x!=y) {
edge[i].vis=true;
juli+=edge[i].w;
//这样就已经实现了把集合相连 
fa[y]=x;
}
}
} int main(){
freopen("in.txt","r",stdin);
init();
sort(edge+,edge++m);
print();
kruskal();
print();
cout<<juli<<endl;
return ;
}
void print(){
for(int i=;i<=m;i++){
cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].w<<" "<<edge[i].vis<<endl;
}
cout<<endl;
}

关于上面代码说几点:

1、father不是边的father,而是点的father

2、46行fa[y]=x;这样就已经实现了把集合相连

3、第31行并查集的两行代码要记下来,一个是叶子,非叶子怎么办

4、第8行结构体里面重载运算符

5、多复习

求最小生成树(暴力法,prim,prim的堆优化,kruskal)的更多相关文章

  1. 图论——最小生成树prim+邻接表+堆优化

    今天学长对比了最小生成树最快速的求法不管是稠密图还是稀疏图,prim+邻接表+堆优化都能得到一个很不错的速度,所以参考学长的代码打出了下列代码,make_pair还不是很会,大体理解的意思是可以同时绑 ...

  2. 最小生成树----prim算法的堆优化

    题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<= ...

  3. prim 堆优化+ kruskal 按秩优化

    #include<iostream> #include<cstdio> #include<cstring> #include<queue> #defin ...

  4. dijkstra(最短路)和Prim(最小生成树)下的堆优化

    dijkstra(最短路)和Prim(最小生成树)下的堆优化 最小堆: down(i)[向下调整]:从第k层的点i开始向下操作,第k层的点与第k+1层的点(如果有)进行值大小的判断,如果父节点的值大于 ...

  5. Codeforces 632F - Magic Matrix(暴力 bitset or Prim 求最小生成树+最小瓶颈路)

    题面传送门 开始挖老祖宗(ycx)留下来的东西.jpg 本来想水一道紫题作为 AC 的第 500 道紫题的,结果发现点开了道神题. 首先先讲一个我想出来的暴力做法.条件一和条件二直接扫一遍判断掉.先将 ...

  6. Prim和Kruskal求最小生成树

    Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小 ...

  7. HDU-1233 还是畅通工程 (prim 算法求最小生成树)

    prim 算法求最小生成树 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Oth ...

  8. Kruskal和Prim算法求最小生成树

    Kruskal算法求最小生成树 测试数据: 5 6 0 1 5 0 2 3 1 2 4 2 4 2 2 3 1 1 4 1 输出: 2 3 1 1 4 1 2 4 2 0 2 3 思路:在保证不产生回 ...

  9. Prim算法和Kruskal算法求最小生成树

    Prim算法 连通分量是指图的一个子图,子图中任意两个顶点之间都是可达的.最小生成树是连通图的一个连通分量,且所有边的权值和最小. 最小生成树中,一个顶点最多与两个顶点邻接:若连通图有n个顶点,则最小 ...

随机推荐

  1. Linux编程 多进程,多线程求解PI(圆周率)

    题目: 链接 多进程: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #define n 1 ...

  2. 解决修改 Linux 下的 PHP 环境变量不生效的方法

    这个问题出现服务器有多个 PHP 版本,php -v和phpinfo()显示两个不同的版本 最近真的,都给朋友解决问题了... phpinfo查看的 php 版本是 7.2.6,到 bash 去使用p ...

  3. jenkins-参数化构建插件:Choice Parameter

    参考: 谢谢大佬的总结: https://www.cnblogs.com/zhaojingyu/p/9862371.html 使用方式 step1: 添加参数,选择Choice Parameter,并 ...

  4. xml解析用正则解决没有标签的文本的解析不出异常

    如  <q>sasas<w>eqwe</w>ddas</q> package com.people.xmlToSql; import java.io.F ...

  5. DataTable删除行Delete与Remove的问题

    DataTable删除行使用Delete后,只是该行被标记为deleted,但是还存在,用Rows.Count来获取行数时,还是删除之前的行数,需要使用datatable.AcceptChanges( ...

  6. appium常见问题02_android内嵌H5页(webview)如何定位

    现在大多数app都是由原生页面和内嵌H5(即webview)组成,app原生页面直接定位即可,那内嵌H5页面要如何定位呢. 相信大多数人用appium做自动化时都有遇到这个问题,小编总结了下工作中该问 ...

  7. 【html】 两栏对比网页,同时滚动

    有的时候需要左右对比环境,而且希望能同时滚动,如下这么拼接就可以了 <html> <head><meta http-equiv="content-type&qu ...

  8. go 语言结构控制

    if  else 结构: #第一种 if condition { // do something } #第二种 if condition { // do something } else { // d ...

  9. 搭建 webpack、react 开发环境(二)

    配置处理样式文件   到目前为止,整个工程的配置已经差不多了,对于 React 更多相关的配置将在后面继续介绍,现在我们先来对目前的工程进行优化. 前面我们学习了搭建 webpack.react 开发 ...

  10. HDU 1029Ignatius and the Princess IV

    Ignatius and the Princess IV Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32767 K ( ...