http://acm.hdu.edu.cn/showproblem.php?pid=1233
思路:按村庄间的距离从小到大排序,选择构成最小生成树
1.prim算法
本题的数据村庄(即顶点的个数)不是很大,故可直接遍历,若数据很大时,就需要用堆来维护每个顶点的当前最短距离
265 MS | 1608 KB |
#include<cstdio>
#include<algorithm>
using namespace std;
#define INF 1e9
const int maxn=105;
int mincost[maxn],cost[maxn][maxn];
bool used[maxn];
int n,t; ///t为顶点个数,n为边的个数
struct cz
{
int a,b,c;
bool operator < (const cz m)const
{
return this->c < m.c;
}
} s[5005];
int prim()
{
for(int i=1; i<=t; i++)
{
mincost[i]=INF;
used[i]=false;
}
mincost[1]=0;
int ans=0;
while(true)
{
int v=0;
for(int u=1; u<=t; u++)
if(!used[u]&&(v==0||mincost[u]<mincost[v]))
v=u;
if(v==0) break;
used[v]=true;
ans+=mincost[v];
for(int u=1; u<=t; u++)
mincost[u]=min(mincost[u],cost[v][u]);
}
return ans;
}
int main()
{
while(scanf("%d",&t),t)
{
n=t*(t-1)/2;
for(int i=1; i<=n; i++)
{
scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
int t1=s[i].a,t2=s[i].b;
cost[t1][t2]=cost[t2][t1]=s[i].c;
}
sort(s+1,s+n+1);
int ans=prim();
printf("%d\n",ans);
}
return 0;
}
2.kruskal算法(可用并查集高效的判断是否属于同一个连通分量)
249 MS | 1580 KB |
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=105;
int par[maxn];
struct cz
{
int a,b,c;
bool operator < (const cz m)const
{
return this->c < m.c;
}
} s[5005];
int Find(int x)
{
int ans=x;
while(par[ans]!=ans)
ans=par[ans];
int c=x;
while(c!=ans)
{
int t=par[c];
par[c]=ans;
c=t;
}
return ans;
}
bool same(int x,int y)
{
return Find(x)==Find(y);
}
void unite(int x,int y)
{
x=Find(x);
y=Find(y);
if(x!=y)
par[x]=y;
}
int main()
{
int n,t;
while(scanf("%d",&t),t)
{
for(int i=1; i<=t; i++)
par[i]=i;
n=t*(t-1)/2;
int ans=0;
for(int i=1; i<=n; i++)
scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
sort(s+1,s+n+1);
for(int i=1; i<=n; i++)
{
int p=s[i].a,q=s[i].b;
if(!same(p,q))
{
unite(p,q);
ans+=s[i].c;
}
}
printf("%d\n",ans);
}
return 0;