题目大意:
给出n,然后再给出n个点的坐标,要连接着n个坐标,使得总距离最小,但是有m对点已经连接,输入m,和m组a和b表示a和b两点已经连接。
思路:
最小生成树
kruskal算法和prim算法
已经链接的两点的权值为0
kruskal代码:
#include <cstring>
#include <stdio.h>
#include <iostream>
using namespace std;
#include <algorithm>
#include <cmath>
const int N = 750;
int n,m;
double x[760];
double y[760];
int p[N * N];
double w[760][760];
struct node {
int x,y;
double d;
}e[N * N + 10];
int cmp(const node & a,const node & b) {
return a.d < b.d;
}
int find(int x) {
int i,j,k = x;
while(k != p[k]) {
k = p[k];
}
i = x;
while( i != k) {
j = p[i];
p[i] = k;
i = j;
}
return k;
}
bool Union(int x,int y) {
int a = find(x);
int b = find(y);
if(a == b)
return false;
else
p[a] = b;
return true;
}
int main() {
int u,v;
while(scanf("%d",&n) != EOF) {
memset(w,0,sizeof(w));
for(int i = 1; i <= n; i++)
scanf("%lf %lf",&x[i],&y[i]);
int num = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i != j) {
w[i][j] = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j]) *(y[i] - y[j]));
}
}
}
scanf("%d",&m);
for(int i = 0; i < m; i++) {
scanf("%d %d",&u,&v);
w[u][v] = w[v][u] = 0;
}
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
e[num].x = i;
e[num].y = j;
e[num++].d = w[i][j];
}
}
sort(e,e + num,cmp);
for(int i = 0; i <= n ; i++)
p[i] = i;
double sum = 0;
for(int i = 0; i < num; i++) {
if(Union(e[i].x,e[i].y))
sum += e[i].d;
}
printf("%.2f\n",sum);
}
return 0;
}
prim代码:
#include <iostream>
using namespace std;
#include <cstring>
#include <stdio.h>
#include <cmath>
#define N 760
int n,m;
double minCost[N];
int h[N];
double w[N][N];
double x[N],y[N];
int pre[N];
double Prim() {
memset(h,0,sizeof(h));
for(int i = 1; i <= n; i++) {
minCost[i] = w[1][i];
pre[i] = 1;
}
h[1] = 1;
double sum = 0;
for(int i = 0; i < n; i++) {
int u = -1;
for(int j = 1; j <= n; j++) {
if(!h[j]) {
if(u == -1 || minCost[j] < minCost[u]) {
u = j;
}
}
}
sum += w[pre[u]][u];
h[u] = 1;
for(int j = 1; j <= n; j++) {
if(!h[j]) {
if(minCost[j] > w[u][j]) {
minCost[j] = w[u][j];
pre[j] = u;
}
}
}
}
return sum;
}
int main() {
int u,v;
while(scanf("%d",&n) != EOF) {
for(int i = 1; i <= n; i++)
scanf("%lf %lf",&x[i],&y[i]);
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
w[i][j] = w[j][i] = sqrt((x[i] - x[j]) *(x[i] - x[j]) + (y[i] - y[j]) *(y[i] - y[j]));
}
}
scanf("%d",&m);
for(int i = 0; i < m; i++) {
scanf("%d %d",&u,&v);
w[u][v] = w[v][u] = 0;
}
printf("%.2lf\n",Prim());
}
return 0;
}