这是我原来的prim太不优美了,今天重打一发
最小生成树两种算法的原理可以看https://www.cnblogs.com/adforce/p/3247437.html写的很好很清楚,我就不班门弄斧了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=INT_MAX;
const ll maxn=6;
bool visit[maxn];
int dir[maxn]={0};
vector<int> path;//存取路径
int Map[maxn][maxn]={ {INF,7,4,INF,INF,INF}, //INF代表两点之间不可达
{7,INF,6,2,INF,4},
{4,6,INF,INF,9,8},
{INF,2,INF,INF,INF,7},
{INF,INF,9,INF,INF,1},
{INF,4,8,7,1,INF}
};//连通情况
ll prim(int cur){//返回最小生成树的路径和
path.clear();
path.push_back(cur);
// cout<<cur<<endl;
int res=0;
int i=0,j=0;
int root=cur;
memset(visit,0,sizeof(visit));
visit[cur]=1;
for(i=0;i<maxn;++i){
dir[i]=Map[root][i];//初始化各个点到树的长度
}
for(i=1;i<maxn;++i){
int temp=INF;
int aid;
for(j=0;j<maxn;++j){
if(!visit[j]&&dir[j]<temp){//找到到这棵树距离最小奥德点
aid=j;
temp=dir[j];
}
}
res+=temp;
visit[aid]=1;
// cout<<aid<<endl;
path.push_back(aid);
for(j=0;j<maxn;++j){//更新各个点到这棵树的路径
if(!visit[j]&&dir[j]>Map[aid][j]){
dir[j]=Map[aid][j];
}
}
}
for(int i=0;i<path.size()-1;++i)//打印路径,或者直接上面的cout就行了
cout<<path[i]<<' ';
cout<<path[path.size()-1]<<endl;
return res;
}
int main(){
//填充Map
cout<<prim(0)<<endl;
return 0;
}
1,prim
瞟了一手基友的代码,用优先队列优化了,所以比原来的prime效率更高
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
const ll maxn=1e5+7;
bool vis[maxn];
struct node{
int to;
int val;
bool operator<(const node &a)const{
return val>a.val;//优先队列默认从大到小
}//所以反一下让他从小到大排序
};
vector<node> G[maxn];
int prim(){
priority_queue<node> q;
int ans=0;
vis[1]=1;
for(int i=0;i<G[1].size();++i){
q.push(G[1][i]);
}
while(!q.empty()){
node tmp=q.top();
q.pop();
if(vis[tmp.to])
continue;
vis[tmp.to]=1;
ans+=tmp.val;
for(int i=0;i<G[tmp.to].size();++i){
q.push(G[tmp.to][i]);
}
}
return ans;
}
int main(){
//填邻接表
cout<<prim()<<endl;
return 0;
}
2,kruscal
感觉并查集加不加入按秩合并,对效率的影响并不是很高(欢迎指正
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
const int size=1e3+5;
int n,father[size],rankk[size];
struct node{//边
int val;
int s;
int e;
node(){};
node(int v,int ss,int ee){
val=v,s=ss,e=ee;
}
void setall(int v,int ss,int ee){
val=v,s=ss,e=ee;
}
}edge[size*size/2];//如果给了边的数量,则用给的,否则会爆
void make_set(){
for(int i=0;i<n;++i){
father[i]=i;
rankk[i]=1;
}
}
int find(int x){//查找父亲节点顺便路径压缩
if(x!=father[x]){
father[x]=find(father[x]);
}
return father[x];
}
//合并x,y所在的两个集合:利用Find_Set找到其中两个
//集合的祖先,将一个集合的祖先指向另一个集合的祖先。
void Union(int x,int y){//按秩合并
x=find(x);
y=find(y);
if(x==y){
return ;
}
else{//不用按秩合并
father[x]=y;
}
/*
if(rankk[x]<rankk[y]){
father[x]=find(y);
}
else{
if(rankk[x]==rankk[y]){
rankk[x]++;
}
father[y]=find(x);
}
*/
}
bool cmp(node a,node b){
return a.val<b.val;
}
int kruskal(int n){//n为边的数量
ll sum=0;
make_set();
for(int i=0;i<n;++i){
if(find(edge[i].s)!=find(edge[i].e)){
Union(edge[i].s,edge[i].e);
sum+=edge[i].val;
}
}
return sum;
}
int main(){
int cnt=0;//边的数量
//建边
sort(edge,edge+cnt,cmp);
cout<<kruskal(cnt)<<endl;
return 0;
}
大佬的总结:
方法上:Kruskal在所有边中不断寻找最小的边,Prim在U和V两个集合之间寻找权值最小的连接,共同点是构造过程都不能形成环。
时间上:Prim适合稠密图,复杂度为O(n * n),因此通常使用邻接矩阵储存,复杂度为O(e * loge),而Kruskal多用邻接表,稠密图 Prim > Kruskal,稀疏图 Kruskal > Prim。
空间上: Prim适合点少边多,Kruskal适合边多点少。
附上几到板子题,供君测试练习
http://hihocoder.com/problemset/problem/1097
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
const ll maxn=1e5+7;
bool vis[maxn];
struct node{
int to;
int val;
node(){}
node(int t,int v){
to=t,val=v;
}
void setall(int t,int v){
to=t,val=v;
}
bool operator<(const node &a)const{
return val>a.val;//优先队列默认从大到小
}//所以反一下让他从小到大排序
};
vector<node> G[maxn];
int prim(){
priority_queue<node> q;
int ans=0;
vis[1]=1;
for(int i=0;i<G[1].size();++i){
q.push(G[1][i]);
}
while(!q.empty()){
node tmp=q.top();
q.pop();
if(vis[tmp.to])
continue;
vis[tmp.to]=1;
ans+=tmp.val;
for(int i=0;i<G[tmp.to].size();++i){
q.push(G[tmp.to][i]);
}
}
return ans;
}
int N;
int main(){
scanf("%d",&N);
int v;
for(int i=1;i<=N;++i){
for(int j=1;j<=N;++j){
scanf("%d",&v);
G[i].push_back(node(j,v));
G[j].push_back(node(i,v));
}
}
cout<<prim()<<endl;
return 0;
}
http://hihocoder.com/problemset/problem/1098
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
const int size=1e5+5;
int father[size],rankk[size];
struct node{//边
int val;
int s;
int e;
node(){};
node(int v,int ss,int ee){
val=v,s=ss,e=ee;
}
void setall(int v,int ss,int ee){
val=v,s=ss,e=ee;
}
}edge[1000005];
void make_set(int n){
for(int i=0;i<n;++i){
father[i]=i;
rankk[i]=1;
}
}
int find(int x){//查找父亲节点顺便路径压缩
if(x!=father[x]){
father[x]=find(father[x]);
}
return father[x];
}
//合并x,y所在的两个集合:利用Find_Set找到其中两个
//集合的祖先,将一个集合的祖先指向另一个集合的祖先。
void Union(int x,int y){//按秩合并
x=find(x);
y=find(y);
if(x==y){
return ;
}
else{//不用按秩合并
father[x]=y;
}
// if(rankk[x]<rankk[y]){
// father[x]=find(y);
// }
// else{
// if(rankk[x]==rankk[y]){
// rankk[x]++;
// }
// father[y]=find(x);
// }
}
bool cmp(node a,node b){
return a.val<b.val;
}
int kruskal(int n){//n为边的数量
ll sum=0;
for(int i=0;i<n;++i){
if(find(edge[i].s)!=find(edge[i].e)){
Union(edge[i].s,edge[i].e);
sum+=edge[i].val;
}
}
return sum;
}
int N,M;
int main(){
int cnt=0;//边的数量
//建边
scanf("%d%d",&N,&M);
make_set(N+1);
int ss,ee,val;
for(int i=0;i<M;++i){
scanf("%d%d%d",&ss,&ee,&val);
edge[i].setall(val,ss,ee);
cnt++;
}
sort(edge,edge+cnt,cmp);
cout<<kruskal(cnt)<<endl;
return 0;
}
HDU 1232畅通工程http://acm.hdu.edu.cn/showproblem.php?pid=1232
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
int n,m;
const int maxn=1e3+7;
bool vis[maxn];
struct node{
int to;
int val;
node(){
}
node(int t,int v){
to=t;
val=v;
}
void setall(int t,int v){
to=t;
val=v;
}
bool operator<(const node&a)const{
return val>a.val;
}
};
vector<node> G[maxn];
int prim(){
memset(vis,0,sizeof(vis));
int res=0;
priority_queue<node> q;
vis[1]=1;
for(int i=0;i<G[1].size();++i){
q.push(G[1][i]);
}
while(!q.empty()){
node t=q.top();
q.pop();
if(vis[t.to])
continue;
vis[t.to]=1;
res+=t.val;
for(int i=0;i<G[t.to].size() ;++i){
q.push(G[t.to][i]);
}
}
return res;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<maxn;++i){
G[i].clear();
}
if(n==0) break;
else{
for(int i=1;i<=n;++i){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
G[x].push_back(node(y,d));
G[y].push_back(node(x,d));
}
if(n<m-1) cout<<"?"<<endl;
else{
int ans=prim();
int i;
for(i=1;i<=m;++i){
if(vis[i]==0){
break;
}
}
if(i>m){
cout<<ans<<endl;
}
else{
cout<<"?"<<endl;
}
}
}
}
return 0;
}
HDU 1879继续畅通工程http://acm.hdu.edu.cn/showproblem.php?pid=1879
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=LONG_LONG_MAX;
const ll inf=LONG_LONG_MIN;
const int maxn=106;
int father[maxn],rankk[maxn];
int N;
struct node {
int s;
int e;
int val;
node() {}
node(int ns,int ne,int v) {
s=ns,e=ne,val=v;
}
void setall(int ns,int ne,int v) {
s=ns,e=ne,val=v;
}
} edge[maxn*maxn>>1];
void make_set(int n) {
for(int i=1; i<=n; ++i) {
father[i]=i;
rankk[i]=1;
}
}
int find(int x) {
if(x!=father[x]) {
father[x]=find(father[x]);
}
return father[x];
}
void Union(int x,int y) {
x=find(x);
y=find(y);
if(x==y)
return ;
if(rankk[x]<rankk[y]){
father[x]=find(y);
}
else{
if(rankk[x]==rankk[y]){
rankk[x]++;
}
father[y]=find(x);
}
}
bool cmp(node a,node b) {
return a.val<b.val;
}
int kruskal(int n) {
int ans=0;
for(int i=0; i<n; ++i) {
if(find(edge[i].s)!=find(edge[i].e)) {
Union(edge[i].s,edge[i].e);
ans+=edge[i].val;
}
}
return ans;
}
int main() {
while(scanf("%d",&N)!=EOF&&N) {
make_set(105);
for(int i=0; i<N*(N-1)/2; ++i) {
int x,y,v,p;
scanf("%d%d%d%d",&x,&y,&v,&p);
edge[i].setall(x,y,v);
if(p==1) {
father[x]=y;
}
}
sort(edge,edge+N*(N-1)/2,cmp);
cout<<kruskal(N*(N-1)/2)<<endl;
}
return 0;
}