求最小生成树(暴力法,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. Spring中Bean的作用域和生命周期

    作用域的种类 Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域.Spring3 为 Bean 定义了五种作用域,具体如下. 1)singleton 单例模式,使用 sing ...

  2. sdb报告-10 错误问题定位

    # sdb报告-10 错误问题定位在sdb 的集群环境中,如果面对的是一个高并发的操作场景,有时候会莫名其妙地报告 -10 错误. 在 sdb 的错误列表中,-10 错误代表:系统错误. 这是一个笼统 ...

  3. Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用

    摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...

  4. Git 提交的正确姿势

    Git 提交的正确姿势:Commit message 编写指南 SCOP范围 middleware core config plugin test type范围 Git 每次提交代码,都要写 Comm ...

  5. PS操作

    笔:B 橡皮:E 新建:C+N 选取套索:L 套索后按Alt,移动 放大:Ctrl + “+” 或 Z 缩小:Ctrl + “-” 或 Alt Z / Alt ,然后用滑轮控制大小 撤销:Ctrl + ...

  6. LeetCode:旋转数组

    最近看了一道题,自己做个过后又参考了网上的解法,为了加深对这个解法的理解和记忆于是有了这篇博客,供自己以后复习用 题目: 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 ...

  7. python多线程的几种情形分析-三种情况

    情形一:默认情况 默认情况,只开启线程,那么,主线程结束,其他子线程可能还没结束. 只使用t=threading.Thead(target=fun),t.start(). import threadi ...

  8. 正则finditer的使用

    import re #\. 是刚需必须有 d+ 必须一个或多个数字 pattern = re.compile(r'\d+\.\d*') d = pattern.finditer('3.14159265 ...

  9. 数据库(四)—— Redis数据库

    目录 redis 一.redis的安装部署 二.redis配置文件 1.基本配置 2.安全配置 3.查看配置信息 三.redis持久化 1.持久化类型 2.RDB持久化 3.AOF持久化(append ...

  10. 三种JavaScript 消息框

    prompt 提示框 <html><head><script type="text/javascript">function disp_prom ...