求最小生成树(暴力法,prim,prim的堆优化,kruskal)
求最小生成树(暴力法,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)的更多相关文章
- 图论——最小生成树prim+邻接表+堆优化
今天学长对比了最小生成树最快速的求法不管是稠密图还是稀疏图,prim+邻接表+堆优化都能得到一个很不错的速度,所以参考学长的代码打出了下列代码,make_pair还不是很会,大体理解的意思是可以同时绑 ...
- 最小生成树----prim算法的堆优化
题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<= ...
- prim 堆优化+ kruskal 按秩优化
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #defin ...
- dijkstra(最短路)和Prim(最小生成树)下的堆优化
dijkstra(最短路)和Prim(最小生成树)下的堆优化 最小堆: down(i)[向下调整]:从第k层的点i开始向下操作,第k层的点与第k+1层的点(如果有)进行值大小的判断,如果父节点的值大于 ...
- Codeforces 632F - Magic Matrix(暴力 bitset or Prim 求最小生成树+最小瓶颈路)
题面传送门 开始挖老祖宗(ycx)留下来的东西.jpg 本来想水一道紫题作为 AC 的第 500 道紫题的,结果发现点开了道神题. 首先先讲一个我想出来的暴力做法.条件一和条件二直接扫一遍判断掉.先将 ...
- Prim和Kruskal求最小生成树
Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小 ...
- HDU-1233 还是畅通工程 (prim 算法求最小生成树)
prim 算法求最小生成树 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Oth ...
- 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 思路:在保证不产生回 ...
- Prim算法和Kruskal算法求最小生成树
Prim算法 连通分量是指图的一个子图,子图中任意两个顶点之间都是可达的.最小生成树是连通图的一个连通分量,且所有边的权值和最小. 最小生成树中,一个顶点最多与两个顶点邻接:若连通图有n个顶点,则最小 ...
随机推荐
- python global和nonlocal的使用
◆global和nonlocal是Python的两个重要变量作用域关键字 1.global用在全局变量,应用场景: 变量定义在函数外部的时候,如果函数里面想改变这个全局变量的值,需要在当前的引用函数里 ...
- python练习题之全选框全不选反选
功能 实现分为两大部分: 第一body 部分,1,通过<li>无序列表标签实现选项的基本样式,通过input的checkbox标签实现里面的复选框功能.用到了标签的嵌套.然后选项的js方法 ...
- 20175126《Java程序设计》第十周学习总结
# 20175126 2016-2017-2 <Java程序设计>第十周学习总结 ## 教材学习内容总结 - 本周学习方式主要为手动敲代码并理解内容学习. -本周学习十二章,主要内容如下: ...
- MySQL清除表数据而保留表结构TRUNCATE TABLE
有时候我们会需要清除一个表格中的所有资料.要达到者个目的,一种方式是使用 DROP TABLE 指令,不过这样整个表格就消失,表无法再被用了.另一种方式就是运用 TRUNCATE TABLE 的指令. ...
- drf:restful概念,类继承关系,drf请求封装,drf请求流程,版本控制组件,认证组件(token),权限组件
1.restful规范 resfful规范的概念最重要: 是一套规范,规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的就是,以前写增删改查的时候需要些四个视图寒素,rest ...
- Cocos2d之FlyBird开发---简介
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 开发FlyBird其实非常的简单,在游戏的核心部分,我们需要实现的只有: 创建一个物理世界(世界设置重力加速度) 在物理世界中添加一个动态 ...
- BZOJ 4765(分块+树状数组)
题面 传送门 "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能计算数列区间和,而普通计算姬能计算树中子树和.更 ...
- Java的动态代理Proxy
概念梳理: 1.什么是动态代理? 答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的接口.代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际 ...
- Java开发中的23种设计模式详解(2)结构型
我们接着讨论设计模式,上篇文章我讲完了5种创建型模式,这章开始,我将讲下7种结构型模式:适配器模式.装饰模式.代理模式.外观模式.桥接模式.组合模式.享元模式.其中对象的适配器模式是各种模式的起源,我 ...
- pychrm和linux进行链接上传代码
众享周知:现在在windows文件中我们有pycharm工具帮我们去编辑python脚本,这会省去我们大把的时间让我们进行更多的脚本编辑.有这样的一种方法,我们可以使用pycharm编辑的脚本上传到l ...