HDU - 1301Jungle Roads(并查集+最小生成树)(内附最小生成树两种算法 克鲁斯特尔算法&&普里姆算法)

Posted wx62a8776062513

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 1301Jungle Roads(并查集+最小生成树)(内附最小生成树两种算法 克鲁斯特尔算法&&普里姆算法)相关的知识,希望对你有一定的参考价值。

题干:

Jungle Roads
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5505    Accepted Submission(s): 3976
Problem Description

【HDU

The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to maintain. The Council of Elders must choose to stop maintaining some roads. The map above on the left shows all the roads in use now and the cost in aacms per month to maintain them. Of course there needs to be some way to get between all the villages on maintained roads, even if the route is not as short as before. The Chief Elder would like to tell the Council of Elders what would be the smallest amount they could spend in aacms per month to maintain roads that would connect all the villages. The villages are labeled A through I in the maps above. The map on the right shows the roads that could be maintained most cheaply, for 216 aacms per month. Your task is to write a program that will solve such problems. 


The input consists of one to 100 data sets, followed by a final line containing only 0. Each data set starts with a line containing only a number n, which is the number of villages, 1 < n < 27, and the villages are labeled with the first n letters of the alphabet, capitalized. Each data set is completed with n-1 lines that start with village labels in alphabetical order. There is no line for the last village. Each line for a village starts with the village label followed by a number, k, of roads from this village to villages with labels later in the alphabet. If k is greater than 0, the line continues with data for each of the k roads. The data for each road is the village label for the other end of the road followed by the monthly maintenance cost in aacms for the road. Maintenance costs will be positive integers less than 100. All data fields in the row are separated by single blanks. The road network will always allow travel between all the villages. The network will never have more than 75 roads. No village will have more than 15 roads going to other villages (before or after in the alphabet). In the sample input below, the first data set goes with the map above. 

 

The output is one integer per line for each data set: the minimum cost in aacms per month to maintain a road system that connect all the villages. Caution: A brute force solution that examines every possible set of roads will not finish within the one minute time limit. 

 

Sample Input
9
A  2  B  12  I  25
B  3  C  10  H  40  I  8
C  2  D  18  G  55
D  1  E  44
E  2  F  60  G  38
F  0
G  1  H  35
H  1  I  35
3
A  2  B  10  C  40
B  1  C  20
0
 


Sample Output
216

30

解题报告:

            最小生成树再来一发。

ac代码:

#include<cstdio>
#include<algorithm>
#include<iostream>

using namespace std;
struct Node
int u,v;
int w;
bool operator< ( const Node & b) const
return w<b.w;

node[105];

int f[100],n,cur,cnt,ans;
void init()
cnt = 0;cur = 0;ans = 0;
for (int i = 0; i <= 27; i++)
f[i] = i;


int getf(int u)
return u==f[u] ? u : f[u]=getf(f[u]);

void merge(int u,int v)
int t1,t2;
t1=getf(u);
t2=getf(v);
if(t1!=t2) f[t2]=t1;

void input()
char ch[5];
int a;
for (int i = 1; i <= n - 1; i++)
scanf("%s %d", ch, &a);
int u = ch[0] - A + 1;
for (int j = 1; j <= a; j++)
int b;
scanf(" %s %d", ch, &b);
int v = ch[0] - A + 1;
node[cnt].u = u;
node[cnt].v = v;
node[cnt].w = b;
cnt++;




int main()
while (scanf("%d", &n) )
getchar();//如果不用getchar 那input中就用%s别用%c
if (n==0) break;
init();
input();
sort(node,node+cnt);
for(int i = 0; i<cnt; i++)
if(getf(node[i].u) != getf(node[i].v) )
merge(node[i].u,node[i].v);
ans+=node[i].w;
cur++;

if(cur==n-1)
break;


printf("%d\\n", ans);

return 0;

贴克鲁斯特尔算法ac代码:(常用!ac代码1就是用此法)

//hdu-1301-Jungle Roads(克鲁斯卡尔)
//题目大意:给出个村庄之间的道路及其维修费;从中选取一些路使道路的维修费最小且保证各村庄
//之间道路畅通;
//解题思路:
//本题最核心的还是构图,由于输入的村庄用字母代替这就需要在构图中将字母替换成数字依次给每个村庄编号;
//需要注意的由于输入的有字符型数据,这就要加一些 getchar()来吸收掉中间的换行空格啥的;
//初始化 per[n] 数组一定要注意,把所有村庄都初始化就行啦;
//具体如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int per[30];
int n,m;
struct fun //定义结构体数组road[100],用来存放起点、终点和距离
int s;
int e;
int p;
road[100];
int cmp(fun x,fun y)

return x.p < y.p;

void init() //初始化 per 数组 ;注意初始完 n个村庄即可;

int d;
for(d=1;d < = n;d++)
per[d]=d;

int find(int x)

int r=x;
while(r!=per[r])
r=per[r];
return r;

bool link(int x,int y)

int fx=find(x),fy=find(y);
if(fx!=fy)
per[fx]=fy;
return true;

return false;

int main()

int j,k,l,sum,i,cnt,a1,a2;
char str1,str2;
while(scanf("%d",&n)&&(n!=0))

getchar();
memset(road,0,sizeof(road));
memset(per,0,sizeof(per));
init();
for(i=1,cnt=1;i < n;i++) //输入数据,并构图;

scanf("%c%d",&str1,&m);
for(j=1;j<=m;j++)

getchar();
scanf("%c%d",&str2,&l);
road[cnt].s=str1-A+1; //将字母编号转化为数字编号并存入结构体数组中
road[cnt].e=str2-A+1;
road[cnt].p=l;
cnt++;

getchar();
//构图完成,剩下的就是克鲁斯卡尔啦;
sort(road,road+cnt,cmp);
sum=0;
for(j=1;j<=cnt;j++)

if(link(road[j].s,road[j].e))
sum+=road[j].p;

printf("%d\\n",sum);

return 0;

贴Prim算法ac代码:

//hdu-1301(普里姆算法)
//本题用普里姆算法求最小生成树直接用普里姆的思想构造函数即可;
//需要注意的是本题再输入数据的是时候要先对 map[1000][1000]中的前 n*n
//个元素初始化为 一个与 min相同或大于它的数;例如,0xfffffff即可;
//(n是结点的个数,由于需要在 n*n 大小的矩阵中构图,所以初始化 n*n 就行);
//为什么要对 map数组初始化呢?一是由于在prim函数中 map要对s[1000]数组赋初值;如果不对map初始化;
//那么,s[]数组中没有数据的就一直为零,与下面的 min比较时,min是永远大于它们的;这样得到的min就一直为零
//最终导致sum为零;还有,不对map按上述初始化,在更新时候也无法完成 ;
#include<stdio.h>
#include<string.h>
#define N 0xfffff
int map[1000][1000];
int n,m,sum,cnt;
void input()

char c1,c2;
int i,j,x,y,price;
cnt=0;
for(i=1;i<=n;i++) //对 map数组初始化为 N ;

for(j=1;j<=n;j++)
map[i][j]=N;

for(i=1;i<n;i++) //输入数据,并构图;

scanf("%c%d",&c1,&m);
x=c1-A+1;
for(j=1;j<=m;j++)

getchar();
scanf("%c%d",&c2,&price);
y=c2-A+1;
map[x][y]=map[y][x]=price;

getchar();


void prim() //普里姆;

int i,j,k,min,v,a,l;
int s[1000],vis[1000];
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
s[i]=map[1][i]; //初始化 s 数组;
s[1]=0; //本身到本身的距离为零
vis[1]=1; //标记第一个点;
sum=0;
for(v=1;v<n;v++)

min=N;
k=1;
for(j=1;j<=n;j++)
if(!vis[j]&&min>s[j])

min=s[j]; //寻找当前最小权值;
k=j;

vis[k]=1; //标记顶点k,表示k已连上树;
sum+=min; //将当前最小权值累加到sum中;
for(a=1;a<=n;a++)

if(!vis[a]&&s[a]>map[k][a]) //标记当前最小权值的顶点后,更新s[] 数组中的权值 ;
s[a]=map[k][a];


printf("%d\\n",sum);

int main()

char c1,c2;
int i,j,x,y,price;
while(scanf("%d",&n)&&(n!=0))

getchar();
input();
prim();

return 0;

 

总结:

      有的时候用%s读字符,不是因为别的,就是因为好处理空格,回车这些烦人的东西!!这件事情告诉我们,少用%c多用%s,少用char多用char[ ] !!

 


以上是关于HDU - 1301Jungle Roads(并查集+最小生成树)(内附最小生成树两种算法 克鲁斯特尔算法&&普里姆算法)的主要内容,如果未能解决你的问题,请参考以下文章

HDU--1301--Jungle Roads(最小生成树)

hdu1301 Jungle Roads 最小生成树

hdu1301 Jungle Roads (最小生成树)

hdu1301 Jungle Roads 基础最小生成树

hduoj-1301 Jungle Roads(最小生成树-克鲁斯卡尔和普里姆求解)

A - Jungle Roads