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的更多相关文章
随机推荐
- SQL常用命令浅析
表操作备注:操作之前使用“use <数据库名>”应连接某个数据库.建表命令:create table <表名> (<字段名 1> <类型 1> [,.. ...
- Java基础中的一些注意点(续)
1.局部(local)变量是在一个方法内定义的变量, 也被称作自动(automatic).临时(temporary)或栈(stack)变量 - 当一个方法被执行时, 局部变量被创建: ...
- 创建第一个UI
创建一个2D UI 制作UI时,首先要创建UI的"根".在Unity顶部NGUI菜单中选择Create,然后选择2D UI. 创建完成后,在Scene窗口中,NGUI自动生成了一个 ...
- [转载]C#字符串加密和解密
using System.Security.Cryptography; using System.IO; //默认密钥向量 private static byte[] Keys = { 0x12, 0 ...
- 关于.net那点事儿
.NET是什么? .NET是开发“托管”软件的平台. 传统环境和.NET环境区别: 传统环境——先将源代码编译为包含机器代码的可执行文件,然后由操作系统加载和执行可执行文件. .NET环境——编译器首 ...
- tortoisesvn的安装与使用
1.下载安装文件,我用的是1.6.同时可以下载一个中文的安装包. 2.我在F盘建立了一个文件夹tortoisesvn,专门用来放置版本目录文件.然后右键这个文件夹,选择tortoisesvn-> ...
- UVA 11294 Wedding
给n对夫妇安排座位,其中0h,0w分别表示新郎,新娘.同一对新郎,新娘不能坐在同一侧,而且互为通奸关系的人不能同时坐在新娘对面. 这道题目真是掉尽节操啊,,,欧美的氛围还是比较开放的. 分析: 首先说 ...
- ANDROID_MARS学习笔记_S02_006_APPWIDGET3_AppWidget发送广播及更新AppWidget
一.简介 二.代码1.xml(1)example_appwidget.xml <?xml version="1.0" encoding="utf-8"?& ...
- Android 三档自定义滑动开关,禁止点击功能的实现,用默认的seekbar组件实现
android三档自定义滑动开关,禁止点击功能的实现,普通开关网上有很多例子,三档滑动开关的则找了整天都没有相关例子,开始用普通开关的源码修改了自己实现了一个类,但效果不如人意,各种边界情况的算法很难 ...
- 【POJ】1054 The Troublesome Frog
题目是非常经典的搜索+剪枝.题意简言之就是,青蛙需要沿着直线踩着踏点通过田地,并且踏点需要至少为3.问哪条路径青蛙踩坏的作物最多.很好的一个条件是青蛙每次移动都是等间距的.题目需要注意将其排序. #i ...