题就是他的名字。。。。。。。。。最小生成树
给n个点,,,,,,之间的距离是gcd(|x1-x2|,|y1-y2|)+1 ,,求总最小距离。。。
先说一下最小生成树:
最小生成树就是一共N个点,,,连接N-1条边,让所有点都连上然后权值还最小(边的长度)
几个算法:
PRIM算法(贪婪)(适合稠密图)
选一个点,任选与他相连的一条边,,,,之后选点有讲究了,,,都是选与已选过的点相连的且权值最小的那个点,,,,,边也存储起来。。。。就是这样~~
Kruskal算法(贪婪)(适合稀疏图)
这个效率会高一点,,,,,,
首先把所有的边都排序,,,,先选最短的,,看可不可以,,,,,然后依次往下选,,,,,可以就选不可以就跳过,,,,,最后就完事了。。。。。
(可不可以要看有没有形成环,,,形成的不能选。。。。所以这里会用到。。。。。。并查集23333333)
这两个算法就不贴代码了,,,,,有好多,,,,,而且理解起来也不难,,,,都可以用矩阵来表示。。。。就完事了
本题代码:
RE 代码:(kruskal+并查集)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include<bits/stdc++.h>
int a[100001][5];
int father[100001],son[100001];
struct node
{
int x,y;
int zhi;
}b[100001];
int unionsearch(int x)
{
return x == father[x] ? x : unionsearch(father[x]);
}
int join(int x, int y) //这里写的真恶心,,,,,,,用原来的并查集模板好了。。。。。
{
int root1, root2;
root1 = unionsearch(x);
root2 = unionsearch(y);
if(root1 == root2)
return 0;
else if(son[root1] >= son[root2])
{
father[root2] = root1;
son[root1] += son[root2];
}
else
{
father[root1] = root2;
son[root2] += son[root1];
}
return 1;
}
int gcd(int a,int b)
{
if(a==0&&b==0) return 0;
if(a==0&&b!=0) return b;
if(b==0&&a!=0) return a;
if(a>b)
{
if(a%b==0) return b;
else return gcd(b,a%b);
}
else
{
if(b%a==0) return a;
else return gcd(a,b%a);
}
}
int cmp(const void *a,const void *b)
{
return (*(node *)a).zhi-(*(node *)b).zhi;
}
int main()
{
int m;
while(scanf("%d",&m)!=EOF)
{
int i,j;
for(i=1;i<=m;i++)
{
scanf("%d %d",&a[i][0],&a[i][1]);
}
int t=1;
memset(b,0,sizeof(b));
for(i=1;i<=m-1;i++)
{
for(j=i+1;j<=m;j++)
{
b[t].x=i;
b[t].y=j;
b[t++].zhi=gcd(abs(a[i][0]-a[j][0]),abs(a[i][1]-a[j][1]))+1;
//printf("***\n");
//printf("%d %d %d**\n",b[t-1].x,b[t-1].y,b[t-1].zhi);
}
}
int sum=0;
qsort(b,t,sizeof(struct node),cmp);
for(i = 0; i <= m; i++)
{
father[i] = i;
son[i] = 1;
}
int q=0;
for(i=1;i<t;i++)
{
if(join(b[i].x,b[i].y))
{
sum+=b[i].zhi;
q++;
//printf("%d***%d\n",b[i].x,b[i].y);
}
if(q==m-1) break;
}
printf("%d\n",sum);
}
return 0;
}
好吧是数组开小了,,,,,开大了就超时了,,,觉得题里给的范围不对吧。。。。。。。简直了。,,,,,哎
一直超时。。。。先打*吧。。
啊啊啊啊。。。。我真蠢,,,,这明显是稠密图,,,,,,要做也是prim啊!!!!
AC代码::(prim算法)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include<bits/stdc++.h>
#include <string.h>
#define MaxInt 0x3f3f3f3f
#define N 1100
int map[N][N],low[N],visited[N];
int a[N][3];
int n;
int gcd(int a,int b)
{
if(a==b) return a;
if(a==0&&b!=0) return b;
if(b==0&&a!=0) return a;
if(a>b)
{
if(a%b==0) return b;
else return gcd(b,a%b);
}
else
{
if(b%a==0) return a;
else return gcd(a,b%a);
}
}
int prim()
{
int i,j,pos,min1,result=0;
memset(visited,0,sizeof(visited));
visited[1]=1;pos=1;
for(i=1;i<=n;i++)
if(i!=pos) low[i]=map[pos][i];
for(i=1;i<n;i++)
{
min1=MaxInt;
for(j=1;j<=n;j++)
if(visited[j]==0&&min1>low[j])
{
min1=low[j];pos=j;
}
result+=min1;
visited[pos]=1;
for(j=1;j<=n;j++)
if(visited[j]==0&&low[j]>map[pos][j])
low[j]=map[pos][j];
}
return result;
}
int main()
{
int i,v,j,ans;
while(scanf("%d",&n)!=EOF)
{
//所有权值初始化为最大
memset(map,MaxInt,sizeof(map));
for(i=1;i<=n;i++)
{
scanf("%d %d",&a[i][0],&a[i][1]);
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
v=gcd(abs(a[i][1]-a[j][1]),abs(a[i][0]-a[j][0]))+1;
//if(v==2) printf("%d %d***\n",i,j);
map[i][j]=map[j][i]=v;
}
ans=prim();
printf("%d\n",ans);
}
return 0;
}
neuoj 1115 AC:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include<bits/stdc++.h>
#include <string.h>
#define MaxInt 500000.0
#define N 1001
double map[N][N],low[N];
int visit[N];
float a[N][3];
int n;
double cal(int i,int j){
return sqrt((a[i][0] - a[j][0])*(a[i][0] - a[j][0]) + (a[i][1] - a[j][1]) * (a[i][1] - a[j][1]));
}
double prim(){
int i;
int m;
double min_w;
double ans;
int s,p;
memset(visit,0,sizeof(visit));
for(i = 0;i < n;i++)
low[i] = MaxInt;
s = 0; ans = 0; m = 1;
while(m < n ){
min_w = MaxInt;
for(i = 1;i < n;i++){
if(!visit[i] && low[i] > map[s][i])
low[i] = map[s][i];
if(!visit[i] && min_w > low[i]){
min_w = low[i];
p = i;
}
}
s = p;
visit[s] = 1;
ans += min_w;
m++;
}
return ans;
}
int main()
{
int i,j;
double ans;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%f %f",&a[i][0],&a[i][1]);
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
//v=sqrt(abs((a[i][1]-a[j][1])*(a[i][1]-a[j][1])+(a[i][0]-a[j][0])*(a[i][0]-a[j][0])));
map[i][j]=cal(i,j);
}
ans=prim();
printf("%.2lf\n",ans);
}
return 0;
}