之前知道有解决最小生成树的prim和kruskal两个算法
貌似两个算法好像针对的题很不一样,系统的解决一下这两个算法
注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。
当图的边数为e时,Kruskal算法所需的时间是O(eloge)。当e = Ω(n^2)时,Kruskal算法比Prim算法差;但当e = o(n^2)时,Kruskal算法比Prim算法好得多。
kruskal----归并边;prim----归并点
并查集详解:https://blog.csdn.net/dellaserss/article/details/7724401
1.kruskal (+并查集)
mark:https://www.cnblogs.com/yoke/p/6697013.html
裸模板题:hdu 1232
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000+10
//Accepted
//Time :31ms
//Memory :1384kB
//Length :668
//Lang :G++
int father[maxn];
void init(int n)//初始化
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
int find(int x)//查
{
return x==father[x]?x:father[x]=find(father[x]);
}
void combine(int a,int b)//并
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=fb;
}
}
int main()
{
int n,m,u,v;
long long ans=0;
while(scanf("%d",&n)&&n)
{
init(n);
ans=0;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
combine(u,v);//连上
}
for(int i=1;i<=n;i++)
{
if(father[i]==i)
ans++;//数一共有几块独立的连通区域
}
printf("%lld\n",ans-1);//ans-1为把独立块联通的线的条数
}
return 0;
}
hdu 4314
切除k个连着的点之间的线 即转化为:k个点的最小生成树
两种情况
1.两边的点都是危险点 这时候要删除 即转化为要计算权值
2.一边是危险点一边不是,要合并两个点的父亲节点 危险点的靠外 即 其父亲节点为新的树的父亲节点
//这样下次再遇到危险点就可删除啦!似乎get思想
#include<bits/stdc++.h>
#define maxn 100000+10
using namespace std;
int flag[maxn];
int fa[maxn];
int t,k,n;
void unit(int n)//初始化
{
for(int i=0;i<n;i++)
fa[i]=i;
}
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void combine(int a,int b)
{
int s1=find(a);
int s2=find(b);
if(s1!=s2)
fa[s1]=s2;
}
struct edge
{
int u,v;
int w;
}e[maxn];
bool cmp(edge a,edge b)
{
return a.w>b.w;//从小到大
}
void kruskal()
{
long long ans=0;
sort(e,e+n-1,cmp);
//初始化
unit(n);
//最小生成顺
for(int i=0;i<n-1;i++)
{
if(flag[find(e[i].u)]&&flag[find(e[i].v)])//两端是危险点 删除 //这棵树两端
{
if(find(e[i].u)!=find(e[i].v))//两个顶点不在同一个集合里边
{
//combine(e[i].u,e[i].v);
ans+=e[i].w;
}
}
else
{
if(flag[find(e[i].u)])//一端是危险点
{
combine(find(e[i].v),find(e[i].u));
}
else
{
combine(find(e[i].u),find(e[i].v));
}
}
}
cout<<ans<<endl;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(flag,0,sizeof(flag));
scanf("%d%d",&n,&k);
for(int i=0;i<n-1;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
for(int i=0;i<k;i++)
{
int a;
scanf("%d",&a);
flag[a]=1;
}
kruskal();
}
}
poj 1251
模板题吧 没啥可解释的
就是输入那块要规避空格啥的 所以用cin 吧 然后突然提醒了我要总结一下各种输入的特点 回头mark一下别人的博客
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 1000
using namespace std;
int father[30];
struct ed
{
int u,v,w;
}point[maxn];//开小了,re了一发55555555 一定要先算算哇
bool cmp(ed a,ed b)
{
return a.w<b.w;
}
void init(int n)
{
for(int i=0;i<n;i++)//i=0或者1要看点哇
{
father[i]=i;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
int combine(int a,int b)
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=fb;//!!!!!!!!!!!!!!!!!!注意不是father【a】=fb
}
}
int main()
{
char ch,sh;
int n;
while(scanf("%d",&n)&&n)
{
init(n);
getchar();
int q=0,time,wl,count=0;
while(q<n-1)
{
cin>>ch>>time;
//int us=
for(int i=count;i<count+time;i++)
{
cin>>sh>>wl;
getchar();
point[i].u=ch-'A';
point[i].v=sh-'A';
point[i].w=wl;
}
q++;
count+=time;
}
//kruskal
int ans=0;
sort(point,point+count,cmp);
for(int i=0;i<count;i++)
{
if(find(point[i].u)!=find(point[i].v))
{
combine(point[i].u,point[i].v);
ans+=point[i].w;
}
}
printf("%d\n",ans);
}
}
poj 1287
//Accepted
//16ms 0.7mb
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define maxn 10000
int father[60];
struct node
{
int u,v,w;
}ed[maxn];
bool cmp(node a,node b)
{
return a.w<b.w;
}
void init(int n)
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
void combine(int a,int b)
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=fb;
}
}
int main()
{
int n,m;
while(cin>>n&&n)
{
init(n);
cin>>m;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&ed[i].u,&ed[i].v,&ed[i].w);
}
//
sort(ed+1,ed+m+1,cmp);
int ans=0;
for(int i=1;i<=m;i++)
{
if(find(ed[i].u)!=find(ed[i].v))
{
ans+=ed[i].w;
combine(ed[i].u,ed[i].v);
}
}
cout<<ans<<endl;
}
}
poj 2031
注意数学公式啊喂,哭了QQQQ
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
//Accepted
//32ms
//0.4mb
int father[1000];
using namespace std;
struct node
{
int p;
double x,y,z,r;
}ed[1000];
struct node2
{
int u,v;
double w;
}ed2[1000000];
bool cmp(node2 a,node2 b)
{
return a.w<b.w;
}
void init(int n)
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
void combine(int a,int b)
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=find(fb);
}
}
double dis(node a,node b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double cul(node a,node b)
{
if(dis(a,b)<=a.r+b.r)
{
return 0;
}
else
{
return dis(a,b)-a.r-b.r;
}
}
int main()
{
int n;
while(cin>>n&&n)
{
init(n);
for(int i=1;i<=n;i++)
{
ed[i].p=i;
scanf("%lf %lf %lf %lf",&ed[i].x,&ed[i].y,&ed[i].z,&ed[i].r);
}
int t=1;
for(int i=1;i<n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j)continue;
else
{
ed2[t].u=ed[i].p;
ed2[t].v=ed[j].p;
ed2[t].w=cul(ed[i],ed[j]);
t++;
}
}
}
t--;
double ans=0;
sort(ed2+1,ed2+t+1,cmp);
//for(int i=1;i<=t;i++)
//{
// printf("%.3f ",ed2[i].w);
//}
for(int i=1;i<=t;i++)
{
if(find(ed2[i].u)!=find(ed2[i].v))
{
combine(ed2[i].u,ed2[i].v);
ans+=ed2[i].w;
}
}
printf("%.3f\n",ans);
}
return 0;
}
poj 2421
//Accepted
//Time 47ms
//Memory 240kB
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 10000+10
using namespace std;
int father[110];
int dis[110][110];
struct node
{
int u,v,w;
}ed[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
void combine(int a,int b)
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=find(fb);
}
}
int main()
{
int n,q;
cin>>n;
init(n);
int t=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int p;
scanf("%d",&p);
if(j>i)
{
ed[++t].u=i;
ed[t].v=j;
ed[t].w=p;
}
}
}
//
long long ans=0;
sort(ed+1,ed+t+1,cmp);
cin>>q;
while(q--)
{
int a,b;
scanf("%d %d",&a,&b);
combine(a,b);
}
for(int i=1;i<=t;i++)
{
if(find(ed[i].u)!=find(ed[i].v))
{
combine(ed[i].u,ed[i].v);
ans+=ed[i].w;
}
}
printf("%lld",ans);
}
zoj 1586
改变一下,把路径长度加上两端的权值
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 1000000+10
using namespace std;
int father[1010];
int prd[1010];
struct node
{
int u,v,w;
}ed[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
{
father[i]=i;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
void combine(int a,int b)
{
int fa=find(a);
int fb=find(b);
if(fa!=fb)
{
father[fa]=find(fb);
}
}
int main()
{
int n,t;
cin>>t;
while(t--)
{
cin>>n;
init(n);
int t=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&prd[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int p;
scanf("%d",&p);
if(j>i)
{
ed[++t].u=i;
ed[t].v=j;
ed[t].w=p+prd[ed[t].u]+prd[ed[t].v];
}
}
}
//
long long ans=0;
sort(ed+1,ed+t+1,cmp);
for(int i=1;i<=t;i++)
{
if(find(ed[i].u)!=find(ed[i].v))
{
combine(ed[i].u,ed[i].v);
ans+=ed[i].w;
}
}
printf("%lld\n",ans);
}
}