您的位置:首页 > 其它

HDU-1875 畅通工程再续-1162 - Eddy's picture(最小生成树,Kruskal 算法实现 )

2014-07-26 22:58 537 查看
 

Problem Description

                      相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为
100元/米。

Input

                    输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。

                    每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。

Output

                   每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

Sample Input

2
2
10 10
20 20
3
1 1
2 2
1000 1000


Sample Output

1414.2
oh!


      最近在搞最小生成树,做了三题套模板的题目,现在才正真理解Kruskal算法。。智商略低了 T T

      与村庄通路一样,只不过岛屿之间的桥长度的类型要用 double 。

      思路如下:

             1) 将所有岛屿的坐标都存入二维数组,该二维数组的下标即是改岛屿的编号。

             2) 将每一个岛屿都与其他剩下的岛屿配对,算出该两个岛屿的距离,距离符合条件,加入代表边的数组。(这里要注意边的数组最大下标需要 maxn*maxn)

             3) 按两个岛屿之间的距离,将代表边的数组从小到大排列。

             4) 核心 kruskal 算法。只需要将模板套上去就好了。注意 : c 个村庄最少 c-1 条边联通这些村庄,如果边数小于c-1,则不构成全连通,所以输出“ oh!”。

            

           

     

/**

HDU - 畅通工程再续 - 1875 -Kruskal

165ms - GUN C++

**/

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

/**
每组数据首先是一个整数C(C <= 100),代表小岛的个数,
接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
**/
const double MINL = 10.000;
const double MAXL = 1000.000;

#define limit(a) ((a)>=MINL)&&((a)<=MAXL) // 判断两个岛屿的距离是否在范围之内

#define FOR(i,n) for( int i = 0; i< n ;++i)

const int MAXV = 100+5;
int isle[MAXV][2];//存储岛屿的坐标
int parent[MAXV];
double ans ;

typedef struct
{
int a;
int b;
double bridge;
}node;

node path[MAXV*MAXV];//存储每条边

double islelen(int &i, int  &j)/** 计算两个岛屿的距离 **/
{
double a = (isle[j][0] - isle[i][0])*1.0;
double b = (isle[j][1] - isle[i][1])*1.0;

return sqrt( a*a+b*b);
}

int build( int &n )/** 构建图 **/
{
int id = 0;
double len;

FOR(i,n-1)/** 第二步 */
for( int j = i+1; j < n ; ++j)
{
len = islelen(i,j);

if ( limit(len) )// 判断两个岛屿的距离是否在范围之内
{
path[id].a = i;
path[id].b = j;
path[id++].bridge = len;
}
}

return id;
}

bool cmp( node a, node b)
{
return a.bridge<b.bridge;
}

int Find ( int *parent, int f)
{
while( parent[f] > 0)
f = parent[f];
return f;
}
void Kruskal( int &id ,int &c)/** Kruskal 核心算法实现 **/
{
memset(parent,0,sizeof(parent));

int n,m,num=0;

ans = 0.0;

FOR(i,id)
{
n = Find( parent, path[i].a);
m = Find( parent , path[i].b);

if( n!=m )
{
parent
= m;
num++;
ans += (double)path[i].bridge;
}
if( num == c-1)break;/** c 个村庄最少 c-1 条边联通这些村庄 **/

}
if( num < c-1 )puts("oh!");
else printf("%.1lf\n",ans*100.0);

}
int main()
{
//freopen("in.txt","r",stdin);
int cas;
scanf("%d",&cas);
while( cas-- )
{
int c;
scanf("%d",&c);
FOR(i,c)
scanf("%d%d",&isle[i][0],&isle[i][1]);/** 第一步 */

if( c==1 )
{
puts("0.0");
continue;
}

int ways = build(c);

sort(path,path+ways,cmp);/** 将距离从小到大排序 第三步 **/

Kruskal(ways,c);

}

return 0;
}



Eddy's picture

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 7123    Accepted Submission(s): 3606


Problem Description

Eddy begins to like painting pictures recently ,he is sure of himself to become a painter.Every day Eddy draws pictures in his small room, and he usually puts out his newest pictures to let his friends appreciate. but the result it can be imagined, the friends
are not interested in his picture.Eddy feels very puzzled,in order to change all friends 's view to his technical of painting pictures ,so Eddy creates a problem for the his friends of you.

Problem descriptions as follows: Given you some coordinates pionts on a drawing paper, every point links with the ink with the straight line, causes all points finally to link in the same place. How many distants does your duty discover the shortest length
which the ink draws?

 

Input

The first line contains 0 < n <= 100, the number of point. For each point, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the point. 

Input contains multiple test cases. Process to the end of file.

 

Output

Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the points. 

 

Sample Input

3
1.0 1.0
2.0 2.0
2.0 4.0

 

Sample Output

3.41

 


#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cctype>
#include <cstring>
#include <cmath>
#include<algorithm>
using namespace std;
const int MX = 100+5;
double point[MX][2];
int par[MX];
double ans;
int n;
typedef struct
{
int a;
int b;
double len;
}node;

node path[MX*MX];

double length( int i ,int j)
{
double a = (point[j][0] - point[i][0])*1.0;
double b = (point[j][1] - point[i][1])*1.0;

return sqrt( a*a+b*b);
}
int build()
{
int ways = 0;
for( int i = 0 ; i < n-1;++i)
for( int j =  i+1;j<n;++j)
{
path[ways].a = i;
path[ways].b = j;
path[ways++].len = length(i,j);
}
return  ways;
}
bool cmp(node a, node b)
{
return a.len<b.len;
}
int Find( int f )
{
while( par[f] )
f = par[f];
return f;
}
double Kruskal(int w)
{
ans = 0.0;
memset(par,0,sizeof(par) );
int num=0,aroot,broot;
for( int i = 0 ; i < w;++i)
{
aroot = Find( path[i].a );
broot = Find( path[i].b);
if( aroot - broot)
{
par[aroot] = broot;
num++;
ans += path[i].len;
}
if( num == n-1)break;
}

return ans;
}
int main()
{

while(cin>>n)
{

for( int i = 0 ;i<n;++i )
cin>>point[i][0]>>point[i][1];
if( n==1 )
{
puts("0.00");
continue;
}
int ways = build();

sort(path,path+ways,cmp);

ans = Kruskal(ways);
printf("%.2lf\n",ans);

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息