点击进入题面
最小生成树模板题,输入为图的邻接矩阵,所以优先考虑prim算法:
#include
#include
using namespace std;
const int maxx=101;
int tot;
int n;
int a[maxx][maxx];
int mincost[maxx];
bool used[maxx];
int prim()
{
int cmp,v;
for (int i = 0; i < n; i++)
{
used[i]=false;
mincost[i]=a[0][i];
}
used[0]=true;
for (int j = 1; j < n; j++)
{
cmp=INT_MAX;
for (int i = 0; i < n; i++)
{
if(!used[i]&&mincost[i]<cmp)
{
cmp=mincost[i];
v=i;
}
}
tot+=cmp;
used[v]=1;
for (int i = 0; i < n; i++)
{
if(!used[i]&&a[v][i]<mincost[i]) mincost[i]=a[v][i];
}
}
return tot;
}
int main()
{
while(cin>>n)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
cin>>a[i][j];
}
}
cout<<prim()<<endl;
tot=0;
}
return 0;
}
当然,也可以使用Kruskal算法:
#include
#include
using namespace std;
const int maxx=101;
const int maxa=10000;
int par[maxx];
int ran[maxx];
void init_union(int n)
{
for (int i = 1; i <= n; i++)
{
par[i]=i;
ran[i]=0;
}
}
int find(int x)
{
return x==par[x]? x: par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if (x==y) return ;
if (ran[x]<ran[y])
{
par[x]=y;
}
else
{
par[y]=x;
if(ran[x]==ran[y]) ran[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int n;
int num;
typedef struct
{
int begin;
int end;
int weight;
}Edge;
Edge e[maxa];
bool cmp(Edge a,Edge b)
{
return a.weight<b.weight;
}
int MiniSpanTree_Kruskal_UnionFind(int n)
{
init_union(n);
int tot=0;
for (int i = 0; i < num; i++)
{
if (!same(e[i].begin,e[i].end))
{
unite(e[i].begin,e[i].end);
tot+=e[i].weight;
}
}
return tot;
}
int main()
{
while(cin>>n)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
cin>>e[num].weight;
e[num].begin=i;
e[num].end=j;
num++;
}
}
sort(e,e+num,cmp);
cout<<MiniSpanTree_Kruskal_UnionFind(n)<<endl;
num=0;
}
return 0;
}
点击进入题面
最大生成树,我们让Kruskal()的边集数组从大到小排列依次添加即可,最后遍历如果有图不为连通图,则输出-1:
#include
#include
using namespace std;
const int maxx=1001;
const int maxa=20001;
struct Edge
{
int x;
int y;
int w;
};
Edge e[maxa];
int par[maxx];
int h[maxx];
bool cmp(Edge x,Edge y)
{
return x.w>y.w;
}
void init(int n)
{
for (int i = 1; i <= n; i++)
{
par[i]=i;
h[i]=0;
}
}
int find(int x)
{
return x==par[x]? x:par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if (h[x]<h[y])
{
par[x]=y;
}
else
{
par[y]=x;
if(h[x]==h[y]) h[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int n,m;
int kruskal()
{
init(n);
int tot=0;
for (int i = 0; i < m; i++)
{
if(!same(e[i].x,e[i].y))
{
unite(e[i].x,e[i].y);
tot+=e[i].w;
}
}
for (int i = 1; i <= n; i++)
{
for (int j = i+1; j <= n; j++)
{
if(!same(i,j)) return -1;
}
}
return tot;
}
int main()
{
while(cin>>n>>m)
{
for (int i = 0; i < m; i++)
{
cin>>e[i].x>>e[i].y>>e[i].w;
}
sort(e,e+m,cmp);
cout<<kruskal()<<endl;
}
return 0;
}
点击进入题面
求最小生成树中的两节点间最大路径,在构建过程中不断更新添加的边的最大值即可:
#include
#include
using namespace std;
const int maxx=2001;
const int maxa=10001;
struct Edge
{
int x;
int y;
int w;
};
Edge e[maxa];
int par[maxx];
int h[maxx];
bool cmp(Edge x,Edge y)
{
return x.w<y.w;
}
void init(int n)
{
for (int i = 1; i <= n; i++)
{
par[i]=i;
h[i]=0;
}
}
int find(int x)
{
return x==par[x]? x:par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if (h[x]<h[y])
{
par[x]=y;
}
else
{
par[y]=x;
if(h[x]==h[y]) h[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int n,m;
int kruskal()
{
init(n);
int tot=0;
for (int i = 0; i < m; i++)
{
if(!same(e[i].x,e[i].y))
{
unite(e[i].x,e[i].y);
if(e[i].w>tot) tot=e[i].w;
}
}
return tot;
}
int main()
{
while(cin>>n>>m)
{
for (int i = 0; i < m; i++)
{
cin>>e[i].x>>e[i].y>>e[i].w;
}
sort(e,e+m,cmp);
cout<<kruskal()<<endl;
}
return 0;
}
点击进入题面
这道题稍微绕一点,首先各边的权值需要自己算,然后求的是最小花费=总权值-最大生成树总权值
。
别忘了节点编号从1开始,因为这个卡了好久…
#include
#include
#include
#include
using namespace std;
const int maxx=10001;
const int maxa=1e8+1;
struct Edge
{
int x;
int y;
double w;
};
Edge e[maxa];
int par[maxx];
int h[maxx];
bool cmp(Edge x,Edge y)
{
return x.w>y.w;
}
void init(int n)
{
for (int i = 1; i <= n; i++)
{
par[i]=i;
h[i]=0;
}
}
int find(int x)
{
return x==par[x]? x:par[x]=find(par[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if (h[x]<h[y])
{
par[x]=y;
}
else
{
par[y]=x;
if(h[x]==h[y]) h[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int n,m;
double kruskal()
{
init(n);
double er=0;
for (int i = 0; i < m; i++)
{
if(!same(e[i].x,e[i].y))
{
unite(e[i].x,e[i].y);
er+=e[i].w;
}
}
return er;
}
pair<int,int> a[maxx];
double exchange(int x,int y)
{
return sqrt((a[x].first-a[y].first)*(a[x].first-a[y].first)+(a[x].second-a[y].second)*(a[x].second-a[y].second));
}
int main()
{
cin>>n>>m;
double tot=0;
for (int i = 0; i < n; i++)
{
cin>>a[i].first>>a[i].second;
}
for (int i = 0; i < m; i++)
{
cin>>e[i].x>>e[i].y;
e[i].w=exchange(e[i].x-1,e[i].y-1);
tot+=e[i].w;
}
sort(e,e+m,cmp);
printf("%.3lf\n",tot-kruskal());
return 0;
}