POJ1838
poj 1838
这道题主要是对并查集的考察,在这道题的解题过程中主要用到的算法就是并查集中的最基本的makeSet,findSet,unionSet
即前篇文章中所提到的:
makeSet(Elem x);主要实现的是,将传入的数据元素初始化为一个集合。
findSet(Elem x); 这个并查集中的原子算法主要实现的是查找到元素x所在的集合,
而这个集合主要使用集合中的祖先元素所唯一标识的。
unionSet(Elem x, Elem y);这个方法主要实现的是合并元素x,元素y所在的集合。
POJ 1838 解题报告
题目具体描述的什么意思就不翻译了,
输入样例中有N,K两个数值。
大致的意思是说,有N*N这么多个区域,区域上有相应的点(x,y)
当两个点point(x1,y1),(x2,y2) 之间是相邻的(neighbor)那么这两个点必须满足下面的条件之一:
1. x1==x2&&|y1-y2|==1
2. y2==y1&&|x1-x2|==1
根据相邻这一判定条件,可以把整个N*N个区域划分成m个区间(region)
即,region中的点是依靠两两之间作为neighbor来连接的。
现如今,需要你输出K个区间(region),并且要求这K个区间对应的区间中的点数之和达到最大。
(也就是说从m个区间中选取K个区间出来,是的这K个区间中的点数之和达到最大)
将m对应的数据结构排序(大到小),然后选取前K个,进行加和,然后进行输出,即可。
大致的算法流程如下:
readIn(N,K) for (i 0-> N-1)
{readIn(trees[i].x , trees[i].y) trees[i].key = i
} makeSet(trees[i].key); //finish initialization qsort(trees.x); for(i 0->N-2)
{
if(trees[i+1].x==trees[i].x && trees[i+1].y- trees[i].y==1)
unionSet(trees[i+1].key, trees[i].key);
} qsort(trees.y); for(i 0 ->N-2)
{
if(trees[i+1].y==trees[i].y && trees[i+1].x- trees[i].x==1)
unionSet(trees[i+1].key, trees[i].key);
} j=0; for(i 0-> N-1)
{
if(trees[i].key 是祖先节点)
setList[j++] = setNumber[trees[i].key];
} after this loop:
the value of j is the length of setList qsort(setList, j, sizeof(int ), compare_method); after this
get setList[0 .. k-1] value and add printf the sum
//union-find set #include<stdio.h>
#include<algorithm> typedef struct
{
int x;
int y;
int key;
}Tree;
//这个数据结构是根据问题而构建的
Tree trees[16001]; //这个数组用来存放节点的
int father[16001]; //father[i]用来表示的是trees[i]这个元素的父节点在trees中的位序下标
int rank[16001]; //这个是用来记录每个集合对应的树模型的树高,秩在并查集中通常以树高表示的,但也有以树状集合中的元素总数来代替的
int setNumber[16001]; //setNumber[i] 对应的是地i个元素的子元素的个数,如果i是它所在集合的祖先节点的话,setNumber[i]
int setList[16001]; //用于记录祖先节点所在的集合对应的集合中的总共的元素的个数的 int cmp(const void *a, const void *b)
{
return *(int *)b - *(int *)a;
}
//这个函数用于根据集合中元素的数目从大到小对setList数组进行排序
//对,因为是大到小排序,所以在返回值上面是参数2-参数1,
//如果是从小到大进行排序,则是参数1-参数2
int cmp_x(const void *a, const void *b)
{
Tree *t1, *t2; t1=(Tree*)a;
t2=(Tree*)b; if(t1->x!= t2->x)
return t1->x-t2->x;
else
return t1->y-t2->y;
}
//在对trees[i].x进行小到大排序的时候,如果trees[i].x的值相等,则排序的顺序将会根据trees[i].y的值从小到大进行相应的排序。
//又因为题中给出每个坐标上只有一棵香蕉树,所以测试数据不会有重复输入两次相同坐标的情况。 int cmp_y(const void *a, const void *b)
{
Tree *t1, *t2; t1 = (Tree*)a;
t2 = (Tree*)b; if(t1->y != t2->y)
return t1->y - t2->y;
else
return t1->x - t2->x;
} void makeSet(int x)
{
father[x] = x;
rank[x] = 0;
setNumber[x]=1;
} int findSet(int x)
{
if(father[x]!=x)
father[x] = findSet(father[x]); return father[x];
} void unionSet(int x, int y)
{
int rootx = findSet(x);
int rooty = findSet(y); if(rootx == rooty) return ;
if(rank[rootx] < rank[rooty])
{
father[rootx] = rooty;
setNumber[rooty] += setNumber[rootx];
} else
{
if(rank[rootx] == rank[rooty])
{
rank[rootx]++;
} father[rooty]=rootx;
setNumber[rootx]+= setNumber[rooty];
}
} int main()
{
int n, k, j, i, ans; scanf("%d %d", &n, &k); for(i = 0 ; i < n ; i++)
{
scanf("%d %d", &trees[i].x, &trees[i].y);
trees[i].key = i; makeSet(trees[i].key);
} qsort(trees, n, sizeof(Tree), cmp_x); for(i = 0 ; i < n-1; i++)
{
if(trees[i].x == trees[i+1].x && trees[i+1].y - trees[i].y ==1)
{
unionSet(trees[i].key, trees[i+1].key);
}
// printf("x:%d y:%d key:%d\n", trees[i].x, trees[i].y, trees[i].key);
} qsort(trees, n, sizeof(Tree),cmp_y); for(i = 0 ; i < n-1; i++)
{
if(trees[i].y == trees[i+1].y && trees[i+1].x-trees[i].x ==1)
{
unionSet(trees[i].key, trees[i+1].key);
} // printf("y:%d x: %d key:%d\n", trees[i].y, trees[i].x, trees[i].key);
} j = 0 ; for(i = 0 ; i < n ; i++)
{
if(father[trees[i].key]==trees[i].key)
{
setList[j++] = setNumber[trees[i].key];
} } qsort(setList, j, sizeof(int), cmp); //printf("region number:%d\n", j); ans = 0 ;
for(i = 0 ; i <k; i++)
{
ans+=setList[i];
//printf("setList[i] %d\n", setList[i]); } printf("%d\n", ans); return 0; }
memory/time/language/code length/date
| 604K | 172MS | C++ | 2197B | 2013-07-24 10:53:57 |
//考虑到这个rank也就是代表每个节点的秩,祖先元素的秩也就是树的高度,在本题中没有太多的实际用途,
//这是因为,在进行unionSet方法的时候,单纯地对元素个数进行比较,
//然后将少的元素所对应的集合的祖先节点所谓到元素多的集合的祖先节点的直系孩子
//也是可以实现相同的结果的,于是把rank变量从代码中进行删除
//然后稍稍更改一下unionSet(int x, int y )这个方法,代码如下:
void unionSet(int x, int y) { int rootx = findSet(x); int rooty = findSet(y);
if(rootx == rooty) return ;
if(setNumber[rootx]< setNumber[rooty])
{
father[rootx] = rooty;
setNumber[rooty] += setNumber[rootx];
}
else
{
father[rooty]=rootx;
setNumber[rootx]+= setNumber[rooty];
}
}
memory/time/language/code length/date
| 540K | 172MS | C++ | 2264B | 2013-07-24 11:28:48 |
POJ1838的更多相关文章
随机推荐
- 在使用Fake framework的时候,为什么有一些函数没有生产mock呢?
在使用Visual studio 2012 的Fake framework 做单元测试的时候,你会发现有一些函数没有生产Stub 或者 Shim的版本,这可能是由于Fake的一些限制导致的,但如何知道 ...
- ionic+angulajs
基于ionic+angulajs的混合开发实现地铁APP 项目源码地址:https://github.com/zhangxy1035/SubwayMap 一.项目简介 在该项目中的地铁app是基于io ...
- 【产品体验】eyepetizer开眼
第一次写博客,内心还有点小激动呢~~本人产品新人,学习中,希望大家多多指教! 先来两张开眼的界面图坐镇—— 开眼简介: appetizer for eyes 即 eyepetizer ...
- JavaScript闭包底层解析
1. 闭包是一个函数,这个函数有权访问另一个函数作用域中的变量,创建闭包最常见的方式,就是在函数内部创建函数.要想彻底搞清其中细节,必须从函数从创建到调用的时候都发生了什么入手 2. 函数第一次被调用 ...
- Oracle数据库的下载和安装
那天分享一下Oracle的下载和安装的过程,有需要的朋友可以借鉴参考一下.如有雷同不胜感激! 首先可以到Oracle的官网下载Oracle的最次年版本的Oracle数据库.一下是个人下载的数据库版本百 ...
- PHP漏洞全解(八)-HTTP响应拆分
本文主要介绍针对PHP网站HTTP响应拆分,站在攻击者的角度,为你演示HTTP响应拆分. HTTP请求的格式 1)请求信息:例如“Get /index.php HTTP/1.1”,请求index.ph ...
- uva 1476 - Error Curves
对x的坐标三分: #include<cstdio> #include<algorithm> #define maxn 10009 using namespace std; do ...
- IDEA如何打包可运行jar的一个问题。
转自http://bglmmz.iteye.com/blog/2058785 背景: 有时候,我们会用IDEA来开发一些小工具,需要打成可运行的JAR包:或者某些项目不是WEB应用,纯粹是后台应用,发 ...
- edX开发部署开篇
edX介绍请参照百度百科 简单的讲,edX是麻省理工和哈佛大学联手创建的开源在线教育平台,任何人都可以在AGPL协议下获取它的源代码,并使用它. 本文的宗旨就是记录安装.使用.开发.维护edX的点点滴 ...
- 使用 jQuery.i18n.properties 实现 Web 前端的国际化
jQuery.i18n.properties 简介 在介绍 jQuery.i18n.properties 之前,我们先来看一下什么是国际化.国际化英文单词为:Internationalization, ...