套模板 直接出
Kruskal
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int father[100];
int n,m;
struct point
{
int u;
int v;
int w;
}a[5000];
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
for(int i=0;i<=100;i++)
father[i]=i;
}
int find(int x) /*查找根节点*/
{
if(father[x]==x)
return x;
return find(father[x]);
}
void merge(int p,int q) /*合并两个集合*/
{
int pp=find(p);
int qq=find(q);
if(pp!=qq)
{
if(pp<qq)
father[qq]=pp;
else
father[pp]=qq;
}
}
int kruskal()
{
initial(); /*初始化*/
int ans=0;
sort(a+1,a+m+1,comp); /*排序*/
for(int i=1;i<=m;i++)
{
int x=find(a[i].u);
int y=find(a[i].v);
if(x!=y) /*两端点不属于同一集合*/
{
ans+=a[i].w;
merge(x,y); /*合并*/
}
}
return ans;
}
int main()
{
int i,sum;
while(~scanf("%d",&n)&&n!=0)
{
int j =1;
for(int i=1; i<n; i++)
{
int value;
char ch[2];
int s;
int k,e;
scanf("%s %d",&ch,&value);/// value代表后面的连接的边数,
s=ch[0]-'A'+1;///起点
while(value--)
{
scanf("%s %d",&ch,&k);
j++;
e=ch[0]-'A'+1;
a[j].u=s;///起点
a[j].v=e;///终点
a[j].w=k;///距离
}
}
m=j;
// for(i=1;i<=m;i++)
// scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
sum=kruskal();
printf("%d\n",sum);
}
return 0;
}
prim
#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
* 数组tree[]用来记录最小生成树的节点
* 数组lowdis[]记录从起点到其余所有点的距离并不断更新
* 数组map[][]记录所有数据两点之间的距离
* n是所有节点的数目,begin_1是起点
* Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i==j) map_1[i][j]=0;
else map_1[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
int i,j,Min,Mindis=0,next;
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++)
{
lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
}
tree[begin_1]=1;//标记起点(即最小生成树中的点)
for(i=1;i<n;i++)
{
Min=INF;
next=-1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&Min>lowdis[j])
{
Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
next=j;
}
}
Mindis+=Min;//记录下整条最小树的长度
tree[next]=1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&lowdis[j]>map_1[next][j])
lowdis[j]=map_1[next][j];//更新lowdis[]数组
}
}
printf("%d\n",Mindis);
}
void init(){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
if(i==j) map_1[i][j]=0;
else map_1[i][j]=INF;
}
}
int main(){
while(cin>>n && n)
{
init();
for(int i=1; i<n; i++){
char u;
int t1;
int t;
cin>>u>>t1;
int tmp1 = u-'A'+1;
while(t1 --)
{
cin>>u>>t;
int tmp2 = u-'A'+1;
map_1[tmp1][tmp2] = map_1[tmp2][tmp1]=t;
}
}
// printf("**\n");
begin_1 = 1;
prime();
}
return 0;
}
B - Networking
多重边,,prim选择最小的建图,,Kruskal直接都存起来排序就好了
这题C++提交一直wa,,改G++就过了 不知道为什么,,
Kruskal
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int father[100];
int n,m;
struct point
{
int u;
int v;
int w;
}a[5000];
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
for(int i=0;i<=100;i++)
father[i]=i;
}
int find(int x) /*查找根节点*/
{
if(father[x]==x)
return x;
return find(father[x]);
}
void merge(int p,int q) /*合并两个集合*/
{
int pp=find(p);
int qq=find(q);
if(pp!=qq)
{
if(pp<qq)
father[qq]=pp;
else
father[pp]=qq;
}
}
int kruskal()
{
initial(); /*初始化*/
int ans=0;
sort(a+1,a+m+1,comp); /*排序*/
for(int i=1;i<=m;i++)
{
int x=find(a[i].u);
int y=find(a[i].v);
if(x!=y) /*两端点不属于同一集合*/
{
ans+=a[i].w;
merge(x,y); /*合并*/
}
}
return ans;
}
int main()
{
int i,sum;
while(~scanf("%d",&n)&&n)
{
cin>>m;
for(int i=1; i<=m; i++)
{
int u,v,w;
cin>>u>>v>>w;
a[i].u = u;
a[i].v = v;
a[i].w = w;
}
sum=kruskal();
printf("%d\n",sum);
}
return 0;
}
prim
C++又可以过,,???是我板子的问题吗///迷。。
#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
* 数组tree[]用来记录最小生成树的节点
* 数组lowdis[]记录从起点到其余所有点的距离并不断更新
* 数组map[][]记录所有数据两点之间的距离
* n是所有节点的数目,begin_1是起点
* Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i==j) map_1[i][j]=0;
else map_1[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
int i,j,Min,Mindis=0,next;
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++)
{
lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
}
tree[begin_1]=1;//标记起点(即最小生成树中的点)
for(i=1;i<n;i++)
{
Min=INF;
next=-1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&Min>lowdis[j])
{
Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
next=j;
}
}
Mindis+=Min;//记录下整条最小树的长度
tree[next]=1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&lowdis[j]>map_1[next][j])
lowdis[j]=map_1[next][j];//更新lowdis[]数组
}
}
printf("%d\n",Mindis);
}
void init(){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
if(i==j) map_1[i][j]=0;
else map_1[i][j]=INF;
}
}
int main(){
while(cin>>n && n)
{
init();
int m;
cin>>m;
for(int i=1; i<=m; i++){
int u,v,w;
cin>>u>>v>>w;
map_1[u][v] = map_1[v][u] = min(map_1[u][v],w);
}
begin_1 = 1;
prime();
}
return 0;
}
C - Building a Space Station
给我们n个点的坐标(x,y,z)和半径r
建图:两个for循环,求出两个球球面的距离。先算出两个球心之间的距离,若该距离<两个半径之和,则两个球面的距离=球心距离-两半径之和;否则,两个球面必定有交点,距离赋值为0
Kruskal
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
const int fa_n = 200+5;
const int maxn = 10050;
int father[fa_n];
int n,m;
double x[maxn];
double y[maxn];
double z[maxn];
double r[maxn];
struct point
{
int u;
int v;
double w;
}a[5000];
int tol = 1;
void addedge(int u,int v,double w)
{
a[++tol].u=u;
a[tol].v=v;
a[tol].w=w;
}
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
for(int i=0;i<=fa_n;i++)
father[i]=i;
}
int find(int x) /*查找根节点*/
{
if(father[x]==x)
return x;
return find(father[x]);
}
void merge(int p,int q) /*合并两个集合*/
{
int pp=find(p);
int qq=find(q);
if(pp!=qq)
{
if(pp<qq)
father[qq]=pp;
else
father[pp]=qq;
}
}
double kruskal()
{
initial(); /*初始化*/
double ans=0;
sort(a+1,a+tol+1,comp); /*排序*/
int cnt = 0;
for(int i=1;i<=tol;i++)
{
int x=find(a[i].u);
int y=find(a[i].v);
if(x!=y) /*两端点不属于同一集合*/
{
ans+=a[i].w;
merge(x,y); /*合并*/
cnt ++;
}
if(cnt == n-1)
{
break;
}
}
return ans;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
tol = 0;//边的数目
for(int i=1; i<=n; i++)
{
scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
for(int j=i-1; j>=1; j--)
{
double dist=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]))-r[i]-r[j];
if (dist<=0) addedge(i,j,0);
else addedge(i,j,dist);
}
}
double sum=kruskal();
printf("%.3f\n",sum);
}
return 0;
}
D - Constructing Roads
给你个图,,已经建好了一些边,,求最小生成树,,prim把建好的边直接为0,,Kruskal先合并已经建好的边
Kruskal
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int fa_n = 100+5;
int father[fa_n];
int ma[1005][1005];
int n,m;
struct point
{
int u;
int v;
int w;
}a[5000];
int tol = 1;
void addedge(int u,int v,int w)
{
a[++tol].u=u;
a[tol].v=v;
a[tol].w=w;
}
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
for(int i=0;i<=fa_n;i++)
father[i]=i;
}
int find(int x) /*查找根节点*/
{
if(father[x]==x)
return x;
return find(father[x]);
}
void merge(int p,int q) /*合并两个集合*/
{
int pp=find(p);
int qq=find(q);
if(pp!=qq)
{
if(pp<qq)
father[qq]=pp;
else
father[pp]=qq;
}
}
int cnt = 0;
int kruskal()
{
int ans=0;
sort(a+1,a+tol+1,comp); /*排序*/
for(int i=1;i<=tol;i++)
{
int x=find(a[i].u);
int y=find(a[i].v);
if(x!=y) /*两端点不属于同一集合*/
{
ans+=a[i].w;
merge(x,y); /*合并*/
cnt ++;
}
if(cnt == n-1)
{
break;
}
}
return ans;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin>>ma[i][j];
}
}
tol = 0;//边的数目
cnt = 0;
initial(); /*初始化*/
for(int i=1; i<=n; i++)
{
for(int j=1; j<=i-1; j++)
{
addedge(i,j,ma[i][j]);
}
}
int m;
cin>>m;
for(int i=1; i<=m; i++)
{
int x,y;
cin>>x>>y;
int u=find(x);
int v=find(y);
if(u!=v) /*两端点不属于同一集合*/
{
merge(x,y); /*合并*/
}
}
// cout<<cnt<<endl;
int sum=kruskal();
printf("%d\n",sum);
}
return 0;
}
prim
#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
* 数组tree[]用来记录最小生成树的节点
* 数组lowdis[]记录从起点到其余所有点的距离并不断更新
* 数组map[][]记录所有数据两点之间的距离
* n是所有节点的数目,begin_1是起点
* Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int a[N][N];
int n;
int begin_1;
void prime()
{
int i,j,Min,Mindis=0,next;
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++)
{
lowdis[i]=a[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
}
tree[begin_1]=1;//标记起点(即最小生成树中的点)
for(i=1;i<n;i++)
{
Min=INF;
for(j=1;j<=n;j++)
{
if(!tree[j]&&Min>lowdis[j])
{
Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
next=j;
}
}
Mindis+=Min;//记录下整条最小树的长度
tree[next]=1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&lowdis[j]>a[next][j])
lowdis[j]=a[next][j];//更新lowdis[]数组
}
}
printf("%d\n",Mindis);
}
void init(){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=INF;
}
}
int main(){
while(cin>>n && n)
{
init();
char c1;
int t;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
{
scanf("%d",&a[i][j]);
}
}
int q;
cin>>q;
while(q --)
{
int x,y;
cin>>x>>y;
a[x][y] = a[y][x] = 0;
}
begin_1 = 1;
prime();
}
return 0;
}
E - QS Network
建图:给你的n*n矩阵不是直接的花费,而是边花费,总花费=边花费+两个端点的花费
prim
#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
* 数组tree[]用来记录最小生成树的节点
* 数组lowdis[]记录从起点到其余所有点的距离并不断更新
* 数组map[][]记录所有数据两点之间的距离
* n是所有节点的数目,begin_1是起点
* Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=INF;
}
*/
const int N = 1000+10;
int tree[N];
int b[N];
int lowdis[N];
int a[N][N];
int n;
int begin_1;
void prime()
{
int i,j,Min,Mindis=0,next;
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++)
{
lowdis[i]=a[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
}
tree[begin_1]=1;//标记起点(即最小生成树中的点)
for(i=1;i<n;i++)
{
Min=INF;
for(j=1;j<=n;j++)
{
if(!tree[j]&&Min>lowdis[j])
{
Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
next=j;
}
}
Mindis+=Min;//记录下整条最小树的长度
tree[next]=1;
for(j=1;j<=n;j++)
{
if(!tree[j]&&lowdis[j]>a[next][j])
lowdis[j]=a[next][j];//更新lowdis[]数组
}
}
printf("%d\n",Mindis);
}
void init(){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=INF;
}
}
int main(){
int t;
cin>>t;
while(t --)
{
cin>>n;
init();
for(int i=1; i<=n; i++)
{
cin>>b[i];
}
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++)
{
scanf("%d",&a[i][j]);
if(i!=j)
{
a[i][j] = a[j][i] =a[i][j]+b[i]+b[j];
}
}
}
// printf("**\n");
begin_1 = 1;
prime();
}
return 0;
}