求最小生成树(暴力法,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. [CSP-S模拟测试]:Lighthouse(哈密顿回路+容斥)

    题目背景 $Billions\ of\ lighthouses...stuck\ at\ the\ far\ end\ of\ the\ sky.$ 题目描述 平面有$n$个灯塔,初始时两两之间可以相 ...

  2. Transition 过渡/转场动画(一)

    UIViewController 的转场效果 当viewController通过push 或 present 进行转场时, 系统自带的动画是从右侧push进来一个新的viewControler (或从 ...

  3. 返回闭包不能引用循环变量,请改写count()函数,让它正确返回能计算1x1、2x2、3x3的函数。

    错误写法: 正确写法:

  4. Html5 学习笔记 【PC固定布局】 实战2 导航栏搜索区域

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8& ...

  5. s11 day106-107 RBAC模块

    一.登录 把权限存在session中 1. rbac models from django.db import models class Permission(models.Model): " ...

  6. JS获取url多个参数及解决中文乱码问题

    function GetQueryString(name) {      var reg = new RegExp("(^|&)"+ name +"=([^&am ...

  7. JavaScript DOM编程艺术-第一章

    发现基础不是很好,补习一下.37买了2本书(dom编程和高级程序设计). 以前读书总是自己勾勾画画,有点没意思.现在写下来,说不定会成为传世经典.哈哈...........随便扯扯淡. 第一天(201 ...

  8. SpringCloud 使用Feign访问服务

    Feign简介: 声明式的Rest  WEB 服务的客户端, https://github.com/OpenFeign/feign.Spring Cloud 提供了Spring-cloud-start ...

  9. [心得]編寫Linux kernel modules時惱人的Makefile

    在一台機器上寫好這樣的Makefile用以編譯modules obj-m:=hello.o CURRENT_PATH:=$(shell pwd) VERSION_NUM:=$(shell uname ...

  10. C#简单的文件依赖缓存的使用

    一,FileCache.aspx页面 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind=& ...