题意就是给你一个长为L的绳子,然后给出n个点,问能不能把所有点都连接在一起
prime算法:
首先两个集合,集合1只含一个顶点A,集合2含有剩下的n-1个顶点,重复下面的操作n-1次
找出集合2中顶点与顶点A连接的最短边,将这个顶点B从集合2移入集合1中,下次使用B继续找顶点
代码实现如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXV 100//后面都会用到
#define INF 32768//INF表示正无穷
typedef struct
{
int x,y;
}Point;
struct MGraph
{
double edges[MAXV][MAXV];//邻接矩阵的边数组
int n;//顶点数,弧度;
};
MGraph g;
double sum;
double distan(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void Prime(MGraph g,int v)
{
double lowcost[MAXV];
int closest[MAXV];
int i,j,k;
double min;
for(i=0;i<g.n;i++)//给lowcost[]和closest赋初值,
{
lowcost[i]=g.edges[v][i];
closest[i]=v;
}
for(i=1;i<g.n;i++)//找出n-1个顶点
{
min=INF;
for(j=0;j<g.n;j++)//在V-U中找出离U最近的顶点k
if(lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j]; k=j;//k记录最近顶点的编号
}
sum +=min;
//cout<<k<<" "<<sum<<endl;
lowcost[k]=0;//标记k已经加入U
for(j=0;j<g.n;j++)//修改数组lowcost和closest
if(g.edges[k][j]!=0 && g.edges[k][j]<lowcost[j])
{
lowcost[j]=g.edges[k][j]; closest[j]=k;
}
}
}
int main()
{
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int n,l,i,j;
Point a[100];
while(cin>>n && n)
{
cin>>l;
g.n=n;
for(i=0;i<n;i++) cin>>a[i].x>>a[i].y;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(i==j) g.edges[i][j]=0.0;
else g.edges[i][j]=distan(a[i],a[j]);
}
sum=0.0;
Prime(g,0);
if(sum<=l) cout<<"Success!"<<endl;
else cout<<"Poor magicpig!"<<endl;
}
return 0;
}
kruskal算法:
因为之前看kruskal算法有点小长,没有prime算法简洁,所以我就给过了,今天好好看了一下,写的第一个kruskal,很多地方没有写简洁,大家可以去之后更新的"kruskal算法 模板"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXV 100//后面都会用到
#define MAXSIZE (100*100)
#define INF 100000//INF表示正无穷
typedef struct
{
int x,y;
}Point;
struct MGraph
{
double edges[MAXV][MAXV];//邻接矩阵的边数组
int n;//顶点数,弧度;
};
MGraph g;
double sum;
double distan(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//并查集
int Father[MAXV]; // Father[i] 表示 i 的父节点
int Rank[MAXV];// rank[ x ] 表示 x 的秩
void MakeSet(int x)
{
Father[ x ] = x;
Rank[ x ] = 1;//不需要使用rank时不需要声明这个
}
int FindSet(int x)
{
while (x != Father[x]) x = Father[x];
return x;
}
void Union(int x, int y)
{
x = FindSet( x ); //查找 x 的祖先
y = FindSet( y ); //查找 y 的祖先
if(x == y) return;
if(Rank[x] > Rank[y])
{
Father[y] = x; //合并后祖先为 x
Rank[x] += Rank[y]; //合并秩
}
else
{
Father[x] = y; //合并后祖先为 y
Rank[y] += Rank[x]; //合并秩
}
}
struct Edge//边
{
int p1,p2;
double val;
};
bool cmp(Edge a,Edge b)
{
return a.val < b.val;//按照边从小到大排序
}
void Kruskal(MGraph g)
{
Edge e[MAXSIZE];//边数组
int i,j,k=0;
//对边进行排序
for(i=0;i<g.n;i++)
for(j=0;j<g.n;j++)
if(g.edges[i][j]!=0 && g.edges[i][j]!=INF)
{
e[k].p1=i; e[k].p2=j; e[k].val=g.edges[i][j];
k++;
}
sort(e,e+k,cmp);
//初始化并查集
for(i=0;i<g.n;i++) MakeSet(i);
//处理
k=1; j=1;
while(k<g.n)
{
if(FindSet(e[j].p1)!=FindSet(e[j].p2))
{
k++; sum +=e[j].val; Union(e[j].p1,e[j].p2);
}
j++;
}
}
int main()
{
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
int n,l,i,j;
Point a[100];
while(cin>>n && n)
{
cin>>l;
g.n=n;
for(i=0;i<n;i++) cin>>a[i].x>>a[i].y;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(i==j) g.edges[i][j]=0.0;
else g.edges[i][j]=distan(a[i],a[j]);
}
sum=0.0;
Kruskal(g);
if(sum<=l) cout<<"Success!"<<endl;
else cout<<"Poor magicpig!"<<endl;
}
return 0;
}