生成树 无向连通图G的一个子图如果是一棵包含G的所有顶点的树
Kruskal算法 并查集的应用
边的长度排序 选取当前最小距离的边 加入图中 看是否能够构成环(用并查集判断是否有环) 没有环就将边加入到图中
ZOJ 1203 给出n个点的坐标 求连接n个点所需线路长度总和的最小值
除了要计算下两点之间的距离外 就是裸的Kruskal
贴个代码就好
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
struct edge
{
int u,v;
double len;
bool operator <(const edge p)const
{
return len<p.len;
}
};
edge e[5000];
double x[110],y[110];
double sum;
int n,m;
int parent[110];//根节点
double LEN(int i,int j)
{
double l=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
return l;
}
void init()
{
for(int i=0;i<n;i++)
parent[i]=-1;
}
//并查集
int Find(int x)// 查找并返回根节点
{
int p;
for(p=x;parent[p]>=0;p=parent[p]);
while(p!=x)//压缩路径
{
int tmp=parent[x];
parent[x]=p;
x=tmp;
}
return p;
}
void Union(int R1,int R2)//将两个不同集合的元素进行合并
{
int r1=Find(R1); int r2=Find(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 x,y; //存储边的两个顶点
init();
for(int i=0;i<m;i++)
{
x=e[i].u; y=e[i].v;
if(Find(x)!=Find(y))
{
sum+=e[i].len;
num++;
Union(x,y);
}
if(num>=(n-1)) break;
}
}
int main()
{
//freopen("ceshi.txt","r",stdin);
int cs=1;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=0;i<n;i++)
scanf("%lf%lf",&x[i],&y[i]);
int cnt=0;
m=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
e[cnt].u=i; e[cnt].v=j;
e[cnt].len=LEN(i,j);
cnt++;
m++;
}
sort(e,e+m);
sum=0.0;
Kruskal();
if(cs>1) puts("");
printf("Case #%d:\n",cs);
printf("The minimal distance is: %.2lf\n",sum);
cs++;
}
return 0;
}
ZOJ 1542
给出n个点 m条边的长度 求出连接n个点最短的长度和
输出选取边中节点的值
直接Kruskal算法就好 注意parent数组的初始化
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int n,m;
struct edge
{
int u,v;
int len;
bool operator <(const edge p)const
{
return len<p.len;
}
};
edge e[15010];
int parent[1010];
int note[1010];
void init()
{
for(int i=0;i<=n;i++)
parent[i]=-1;//注意 因为每个节点的值都是大于等于1小于等于n的 所有n要包括其中
}
int Find(int x)
{
int p;
for(p=x;parent[p]>=0;p=parent[p]);
while(p!=x)
{
int tmp=parent[x];
parent[x]=p;
x=tmp;
}
return p;
}
void Union(int R1,int R2)
{
int r1=Find(R1),r2=Find(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()
{
init();
int mx=-1;
int x,y;
int cnt=0;
for(int i=0;i<m;i++)
{
x=e[i].u; y=e[i].v;
if(Find(x)!=Find(y))
{
mx=max(mx,e[i].len);
note[cnt++]=i;
Union(x,y);
}
if(cnt>=(n-1))
{
printf("%d\n",mx);
break;
}
}
}
int main()
{
//freopen("ceshi.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<m;i++)
{
int x,y,l;
scanf("%d%d%d",&x,&y,&l);
e[i].u=x; e[i].v=y;
e[i].len=l;
}
sort(e,e+m);
// cout<<"whwhw"<<endl;
Kruskal();
printf("%d\n",n-1);
for(int i=0;i<n-1;i++)
{
int tmp=note[i];
printf("%d %d\n",e[tmp].u,e[tmp].v);
}
}
return 0;
}
又水了两个题。。。
zoj 1406
没什么好说的 主要是读入的问题
我一开始用 scanf 读入 因为里面有字符 有数字 有空格 换行 我就一个个的去读入 但是有问题 不造为什么
用cin直接读入就对了。。。郁闷。。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int n;
struct edge
{
int u,v;
int len;
bool operator<(const edge p)const
{
return len<p.len;
}
};
edge e[80];
int parent[27];
int res;
int cnt;//边的条数
void init()
{
for(int i=0;i<27;i++)
parent[i]=-1;
}
int Find(int x)
{
int p;
for(p=x;parent[p]>=0;p=parent[p]);
while(p!=x)
{
int tmp=parent[x];
parent[x]=p;
x=tmp;
}
return p;
}
void Union(int R1,int R2)
{
int r1=Find(R1),r2=Find(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()
{
init();
int num=0;
for(int i=0;i<cnt;i++)
{
int x,y;
x=e[i].u; y=e[i].v;
if(Find(x)!=Find(y))
{
res+=e[i].len;
num++;
Union(x,y);
}
if(num>=n-1) break;
}
}
int main()
{
//freopen("ceshi.txt","r",stdin);
while(cin>>n)
{
if(n==0) break;
cnt=0;
for(int i=0;i<n-1;i++)
{
char a,b;
int x,y,l;
cin>>a>>y;
x=a-'A';//从0开始
for(int j=0;j<y;j++)
{
cin>>b>>l;
int z=b-'A';
e[cnt].u=x; e[cnt].v=z;
e[cnt].len=l;
cnt++;
}
// scanf("\n");
}
res=0;
// cout<<"11111111"<<endl;
sort(e,e+cnt);
Kruskal();
// cout<<"222"<<endl;
printf("%d\n",res);
}
return 0;
}
ZOJ 1372
没什么说的 主要是判重的问题
我是用三维map存储状态 直接判断就可以了。。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <map>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
map<int,map<int,int> > mp;
int n,m;
int res;
int parent[60];
struct edge
{
int u,v;
int len;
bool operator<(const edge p)const
{
return len<p.len;
}
};
edge e[3000];
void init()
{
for(int i=0;i<=n;i++)
parent[i]=-1;
}
int Find(int x)
{
int p;
for(p=x;parent[p]>=0;p=parent[p]);
while(p!=x)
{
int tmp=parent[x];
parent[x]=p;
x=tmp;
}
return p;
}
void Union(int R1,int R2)
{
int r1=Find(R1),r2=Find(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()
{
init();
int num=0;
for(int i=0;i<m;i++)
{
int x,y;
x=e[i].u; y=e[i].v;
if(Find(x)!=Find(y))
{
res+=e[i].len;
num++;
Union(x,y);
}
if(num>=n-1) break;
}
}
int main()
{
//freopen("ceshi.txt","r",stdin);
//int cs=1;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
scanf("%d",&m);
for(int i=1;i<=50;i++)
for(int j=1;j<=50;j++)
mp[i][j]=0;
for(int i=0;i<m;i++)
{
int x,y,l;
scanf("%d%d%d",&x,&y,&l);
if(!mp[x][y])
{
e[i].u=x; e[i].v=y;
e[i].len=l;
mp[x][y]=1;
}
else
{
e[i].len=min(l,e[i].len);
}
}
sort(e,e+m);
res=0;
Kruskal();
printf("%d\n",res);
// cout<<"case "<<cs++<<endl;
}
return 0;
}