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的更多相关文章

随机推荐

  1. GPU CUDA常量内存使用

    #include <cuda.h> #include <stdio.h> int getMulprocessorCount(){ cudaDeviceProp prop; cu ...

  2. MVC-内容详情页显示内容

    @model InfoDataProvider.DataModel.FAQ_ContentUser 内容Content字段:如果里面有html标签. @Html.DisplayFor(p => ...

  3. C和BlockCode

    在使用code block的时候,需要先build,然后再run,否则run的还是上次编译的内容.

  4. WLLCM这五个字母全排列数目

           经过训练的话一眼看出来是5!/2!:我想的是先排WLCM那么是4!,5个位置,由于L左右两边的位置其实是一样的(再插入的还是L),索以结果是4*4!,这样重复了,看下图.         ...

  5. AOT

    预 (AOT) 编译器 https://angular.cn/docs/ts/latest/cookbook/aot-compiler.html To run your app in AoT mode ...

  6. 如何将CELERY放到后台执行?

    在作正式环境,这个是必须的. 于是找了两小时文档, 以下这个方法,相对来说好实现. 就是要注意supervisord.conf的目录存放位置. 放在DJANGO的PROJ目录下,是最佳位置. http ...

  7. 编码问题 关于hibernate jdbc数据库连接在xml配置与在properties文件配置的差异

    在properties中,&字符不需要转义,因此在连接数据库的时候使用编码的地方直接使用&即可: driverClass=com.mysql.jdbc.Driver jdbcUrl=j ...

  8. Tomcat 6 支持 NIO -- Tomcat的四种基于HTTP协议的Connector性能比较(转载)

    Tomcat从5.5版本开始,支持以下四种Connector的配置分别为: <Connector port="8081" protocol="org.apache. ...

  9. [Gauss]POJ2947 Widget Factory

    题意: 有n种小工具要加工,每种工具的加工时间为3到9天,给了m条加工记录.  每条记录 X $s_1$ $s_2$ 分别代表 这个工人在$s_1$到$s_2$(前闭后闭)的时间里加工了X件小工具   ...

  10. 你所不知道的string.xml

    String 能被应用程序或者其他资源文件(比如layout XML)引用的单个字符串. 注意:字符串是简单类型资源,是用名称(name)(而非XML文件名)来直接引用的.因此,在一个XML文件里,可 ...