求最小生成树(暴力法,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. LintCode之合并排序数组

    题目描述: 我的代码: public class Solution { /* * @param A: sorted integer array A * @param B: sorted integer ...

  2. Mac上VMWare Fusion配置多台cent os

    一.创建虚拟机(准备工作) 1.使用VMWare Fusion 创建第一台虚拟机 2.选择操作系统(本次使用的是使用cent os 6.5 64bit 系统) 3.选择磁盘大小(楼主mac上的磁盘大小 ...

  3. outlook使用inline style回复邮件

    Reply with inline comments within the original message text When you reply to email messages in Outl ...

  4. 杂项:JFB-权限设置

    ylbtech-杂项:JFB-权限设置 1. 家政经理返回顶部 1. if (UserContext.GetTeamId() == (int)UserType.Manager) { condition ...

  5. day 107radis非关系型数据库

    http://www.cnblogs.com/wupeiqi/articles/5132791.html   参考邮件. radis : 1. NoSql 2. 缓存在内存中 3.支持数据持久化 二. ...

  6. UVA10271_Chopsticks

    Chopsticks 大致就是有一堆筷子,知道了他们的长度,现在选长度为abc的三个筷子a<=b<=c为一对筷子,质量为(a-b)平方,现在选k双这样的筷子,求质量最小 思路: 第一次看到 ...

  7. BZOJ 4765(分块+树状数组)

    题面 传送门 "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能计算数列区间和,而普通计算姬能计算树中子树和.更 ...

  8. 【笔记目录1】【jessetalk 】ASP.NET Core快速入门_学习笔记汇总

    当前标签: ASP.NET Core快速入门 共2页: 1 2 下一页  任务50:Identity MVC:DbContextSeed初始化 GASA 2019-03-02 14:09 阅读:16 ...

  9. LeetCode Array Easy 268. Missing Number

    Description Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one th ...

  10. web前端架构师学习流程

    JavaScript 开发(高级) 系统知识 1.1ECMAScript标准的发展过程,ES6语言对JavaScript的改进: 1.2ES6中语法层面的新特性(let.const.参数扩展.模块化等 ...