这道题花了我n多时间,最关键的是我的时间不是花在算法上,而是其中一个小的临界值上.照着模板抄下来,途中打算自己写,结果就是找错找了一下午.这也就是看在在假期里时间比较宽松可以这样浪费,这样下去,可不是办法.
思路:在一个平面上n个点且两两相连,每边有权值,让你找出n-1个点形成无回路的连通图,当然是权值最小;题目给你的是n个城市的坐标,第一个为x坐标,第二个为y坐标,这与kruskal算法直接给出顶点数与边数还有权值有点变化,这可能就是编程的最大乐趣了!我先这样处理:取两个double数组X[],Y[],接下来将每个坐标的x,y分别写入,Then,double d=sqrt((xi-xj)^2+(yi-yj)^2),得到权值,在与各顶点封装排序.还有一点是计算d的时候,举个测例:由5个城市的坐标怎么得到其中1个城市与其他4个城市的距离与顶点表示?
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
//scanf("%f%f",&x,&y);自己第一次写的
//两点之间的距离
d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
edges[m].u=i;
edges[m].v=j;
edges[m].w=d;
m++;
}
}
这样,会出现
0-->1=d;
0-->2,
0-->3
...
我的关键在于kruskal算法的理解与应用上自己还有太大的差距,还有并查集.
最最关键:这道题没有通过
思路:在一个平面上n个点且两两相连,每边有权值,让你找出n-1个点形成无回路的连通图,当然是权值最小;题目给你的是n个城市的坐标,第一个为x坐标,第二个为y坐标,这与kruskal算法直接给出顶点数与边数还有权值有点变化,这可能就是编程的最大乐趣了!我先这样处理:取两个double数组X[],Y[],接下来将每个坐标的x,y分别写入,Then,double d=sqrt((xi-xj)^2+(yi-yj)^2),得到权值,在与各顶点封装排序.还有一点是计算d的时候,举个测例:由5个城市的坐标怎么得到其中1个城市与其他4个城市的距离与顶点表示?
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
//scanf("%f%f",&x,&y);自己第一次写的
//两点之间的距离
d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
edges[m].u=i;
edges[m].v=j;
edges[m].w=d;
m++;
}
}
这样,会出现
0-->1=d;
0-->2,
0-->3
...
我的关键在于kruskal算法的理解与应用上自己还有太大的差距,还有并查集.
最最关键:这道题没有通过 #include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <math.h>
using namespace std;
#define MAXN 105
#define MAXM 5050
double X[MAXN],Y[MAXN];//用来存储x,y的坐标,其他关于坐标的运算可以模仿
int i,n,j,m,mi,x,y;//循环变量,frist i defined it in main()
double sum=0.0;//总权值
struct edge
{
int u,v;//顶点
double w;//权值,注意类型
}edges[MAXN];
int parent[MAXN];
int cmp(const void *a,const void *b)
{
// return (*(edge *))我想用另种方法
edge aa=*(const edge *)a;edge bb=*(const edge *)b;
if (aa.w>bb.w)
return 1;
else
return -1;
}
void UFset()//初始化
{
for(i=0;i<=mi;i++)
parent[i]=-1;
}
int Find(int x)//查找并返回节点x所属集合的根节点
{
int s=x;
for(;parent[s]>=0;s=parent[s])
;
while(s!=x)//优化方案——压缩路径,使后续查找更加方便,但为什么呢
{
parent[x]=s;
x=s;
}
return s;
}
void Union(int R1,int R2)
{
int r1=Find(R1),r2=Find(R2);// r1,r2分别为根节点
int tmp=parent[r1]+parent[r2];
if(parent[r1]>parent[r2])//优化方案,路径加权
{
parent[r1]=r2;parent[r2]=tmp;
}
else
{
parent[r2]=r1;parent[r1]=tmp;
}
}
void kruskal()
{
int num=0;
//int u,v;
UFset();
for(i=0;i<mi;i++)
{
x=edges[i].u;y=edges[i].v;
if(Find(x)!=Find(y))
{
//printf("%d %d",x,y);
sum+=edges[i].w;
num++;
Union(x,y);
}
if(num>=n-1)
break;
}
}
int main()
{
// freopen("in.txt","r",stdin);
// int n;//测试数据的个数
double d;//可以不要了
//int m=0,mi;//边的标志,中间变量
int kcase=1;
while(1)
{
cin>>n;
if(n==0)
break;
//输入各个城市的坐标
for(i=0;i<n;i++)
scanf("%lf%lf",&X[i],&Y[i]);//这一句关键去了,没有%lf不读数据
int m=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
//scanf("%f%f",&x,&y);自己第一次写的
//两点之间的距离
d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
edges[m].u=i;
edges[m].v=j;
edges[m].w=d;
m++;
}
}
mi=m;//我先自己试试,还是用这个吧,比较好用
qsort(edges,mi,sizeof(edges[0]),cmp);
sum=0.0;
kruskal();
// for(i=0;i<mi;i++)
// printf("%d-->%d=%0.2f\n",edges[i].u,edges[i].v,edges[i].w);
if(kcase>1)
cout<<endl;
printf("Case #%d:\n",kcase);
printf("The minimal distance is: %0.2f\n",sum);
kcase++;
}
return 0;
}
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <math.h>
using namespace std;
#define MAXN 105
#define MAXM 5050
double X[MAXN],Y[MAXN];//用来存储x,y的坐标,其他关于坐标的运算可以模仿
int i,n,j,m,mi,x,y;//循环变量,frist i defined it in main()
double sum=0.0;//总权值
struct edge
{
int u,v;//顶点
double w;//权值,注意类型
}edges[MAXN];
int parent[MAXN];
int cmp(const void *a,const void *b)
{
// return (*(edge *))我想用另种方法
edge aa=*(const edge *)a;edge bb=*(const edge *)b;
if (aa.w>bb.w)
return 1;
else
return -1;
}
void UFset()//初始化
{
for(i=0;i<=mi;i++)
parent[i]=-1;
}
int Find(int x)//查找并返回节点x所属集合的根节点
{
int s=x;
for(;parent[s]>=0;s=parent[s])
;
while(s!=x)//优化方案——压缩路径,使后续查找更加方便,但为什么呢
{
parent[x]=s;
x=s;
}
return s;
}
void Union(int R1,int R2)
{
int r1=Find(R1),r2=Find(R2);// r1,r2分别为根节点
int tmp=parent[r1]+parent[r2];
if(parent[r1]>parent[r2])//优化方案,路径加权
{
parent[r1]=r2;parent[r2]=tmp;
}
else
{
parent[r2]=r1;parent[r1]=tmp;
}
}
void kruskal()
{
int num=0;
//int u,v;
UFset();
for(i=0;i<mi;i++)
{
x=edges[i].u;y=edges[i].v;
if(Find(x)!=Find(y))
{
//printf("%d %d",x,y);
sum+=edges[i].w;
num++;
Union(x,y);
}
if(num>=n-1)
break;
}
}
int main()
{
// freopen("in.txt","r",stdin);
// int n;//测试数据的个数
double d;//可以不要了
//int m=0,mi;//边的标志,中间变量
int kcase=1;
while(1)
{
cin>>n;
if(n==0)
break;
//输入各个城市的坐标
for(i=0;i<n;i++)
scanf("%lf%lf",&X[i],&Y[i]);//这一句关键去了,没有%lf不读数据
int m=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
//scanf("%f%f",&x,&y);自己第一次写的
//两点之间的距离
d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]));
edges[m].u=i;
edges[m].v=j;
edges[m].w=d;
m++;
}
}
mi=m;//我先自己试试,还是用这个吧,比较好用
qsort(edges,mi,sizeof(edges[0]),cmp);
sum=0.0;
kruskal();
// for(i=0;i<mi;i++)
// printf("%d-->%d=%0.2f\n",edges[i].u,edges[i].v,edges[i].w);
if(kcase>1)
cout<<endl;
printf("Case #%d:\n",kcase);
printf("The minimal distance is: %0.2f\n",sum);
kcase++;
}
return 0;
}