HDU 1198 Farm Irrigation (并检查集合 和 dfs两种实现)
Farm Irrigation
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4977 Accepted Submission(s): 2137
to K, as Figure 1 shows.

Figure 1
Benny has a map of his farm, which is an array of marks denoting the distribution of water pipes over the whole farm. For example, if he has a map
ADC
FJK
IHE
then the water pipes are distributed like

Figure 2
Several wellsprings are found in the center of some squares, so water can flow along the pipes from one square to another. If water flow crosses one square, the whole farm land in this square is irrigated and will have a good harvest in autumn.
Now Benny wants to know at least how many wellsprings should be found to have the whole farm land irrigated. Can you help him?
Note: In the above example, at least 3 wellsprings are needed, as those red points in Figure 2 show.
M or N denotes the end of input, else you can assume 1 <= M, N <= 50.
2 2
DK
HF 3 3
ADC
FJK
IHE -1 -1
2
3
题意:有如上图11种土地块,块中的绿色线条为土地块中修好的水渠,如今一片土地由上述的各种土地块组成,须要浇水,问须要打多少口井。
比如以下这个土地块
ADC
FJK
IHE
then the water pipes are distributed like

如图对于能相连的地仅仅须要打一口井。所以以上须要打三口井就能浇全部的块。稍加分析就可得出本质上就是集合的合并,最后求有几个集合的问题,非常easy想到并查集。仅仅须要对每一个地块与右方和下方的地块进行合并就可以。
合并之前先推断能否连通。若能连通则合并。不能连通,则不能合并。
能连通的时候就是正常的并查集了。此题有个问题,题目说最大50*50个地块,可是提交一直出错,看别人说的改成550*550直接A了,所以说这里题目叙述有误。
后来想了想。能够把每一个地块的四个方向用二进制来表示,用位运算来推断可连性。
#include <cstdio>
#include <cstdlib>
#include <climits> const int MAX = 550; //存储11中类型的土地,二维中的0 1 2 3分别代表这样的类型的土地的左上右下
//为1表示这个方向有接口。为0表示这个方向没有接口
const int type[11][4]={{1,1,0,0},{0,1,1,0},
{1,0,0,1},{0,0,1,1},
{0,1,0,1},{1,0,1,0},
{1,1,1,0},{1,1,0,1},
{1,0,1,1},{0,1,1,1},
{1,1,1,1}
}; const bool VERTICAL = true; //pre数组就是正常的并查集中所用,可是在合并的时候要注意将二维坐标转换成一维的标号,此处用行优先
int pre[MAX*MAX+1],cnt,m,n;
char farm[MAX][MAX]; void init(int n){
int i;
for(i=1;i<=n;++i){
pre[i] = i;
}
cnt = n;
} int root(int x){
if(x!=pre[x]){
pre[x] = root(pre[x]);
}
return pre[x];
} void merge(int ax,int ay,int bx,int by,bool dir){
if(bx>n || by>m)return;//超出地图的部分不进行合并
bool mark = false;//标识两块地是否可连
int ta,tb;//两点的类型值0-10 ta = farm[ax][ay]-'A';
tb = farm[bx][by]-'A'; if(dir){//竖直方向推断可连性
if(type[ta][3] && type[tb][1])mark = true;
}else{//水平方向推断可连性
if(type[ta][2] && type[tb][0])mark = true;
} if(mark){//仅仅要可连就合并,这就是正常的并查集了
int fx = root((ax-1)*m+ay);
int fy = root((bx-1)*m+by);
if(fx!=fy){
pre[fy] = fx;
--cnt;
}
}
} int main(){
//freopen("in.txt","r",stdin);
int i,j;
while(scanf("%d %d",&n,&m)!=EOF){
if(n==-1 && m==-1)break;
init(n*m);
for(i=1;i<=n;++i){
scanf("%s",farm[i]+1);
}
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
merge(i,j,i+1,j,VERTICAL);
merge(i,j,i,j+1,!VERTICAL);
}
}
printf("%d\n",cnt);
}
return 0;
}
下面是位运算的实现,就相对简化了点。
#include <cstdio>
#include <cstdlib>
#include <climits> const int MAX = 550; const int type[11] = {3,6,9,12,10,5,7,11,13,14,15};
const bool VERTICAL = true; //pre数组就是正常的并查集中所用,可是在合并的时候要注意将二维坐标转换成一维的标号。此处用行优先
int pre[MAX*MAX+1],cnt,m,n;
char farm[MAX][MAX]; void init(int n){
int i;
for(i=1;i<=n;++i){
pre[i] = i;
}
cnt = n;
} int root(int x){
if(x!=pre[x]){
pre[x] = root(pre[x]);
}
return pre[x];
} void merge(int ax,int ay,int bx,int by,bool dir){
if(bx>n || by>m)return;//超出地图的部分不进行合并
bool mark = false;//标识两块地是否可连
int ta,tb;//两点的类型值0-10 ta = farm[ax][ay]-'A';
tb = farm[bx][by]-'A'; if(dir){//竖直方向推断可连性
if(((type[ta]>>3) & 1) && ((type[tb]>>1) & 1))mark = true;
}else{//水平方向推断可连性
if(((type[ta]>>2) & 1) && (type[tb] & 1))mark = true;
} if(mark){//仅仅要可连就合并,这就是正常的并查集了
int fx = root((ax-1)*m+ay);
int fy = root((bx-1)*m+by);
if(fx!=fy){
pre[fy] = fx;
--cnt;
}
}
} int main(){
//freopen("in.txt","r",stdin);
int i,j;
while(scanf("%d %d",&n,&m)!=EOF){
if(n==-1 && m==-1)break;
init(n*m);
for(i=1;i<=n;++i){
scanf("%s",farm[i]+1);
}
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
merge(i,j,i+1,j,VERTICAL);
merge(i,j,i,j+1,!VERTICAL);
}
}
printf("%d\n",cnt);
}
return 0;
}
下面是dfs实现
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cstring> const int MAX = 550; const int type[11] = {3,6,9,12,10,5,7,11,13,14,15};
const int dirx[4] = {0,-1,0,1},diry[4]={-1,0,1,0};
int m,n;
char farm[MAX][MAX];
int visit[MAX][MAX]; bool yes(int ax,int ay,int bx,int by,int dir){
bool mark = false;
int ta,tb; if(bx<1 || bx>n || by<1 || by>m)return false;
ta = farm[ax][ay]-'A';
tb = farm[bx][by]-'A'; if(dir==0){//向左
if((type[ta] & 1) && ((type[tb]>>2) & 1))mark = true;
}else if(dir==1){//向上推断可连性
if(((type[ta]>>1) & 1) && ((type[tb]>>3) & 1))mark = true; }else if(dir==2){//水平向右
if(((type[ta]>>2) & 1) && (type[tb] & 1))mark = true;
}else{//水平向下推断可连性
if(((type[ta]>>3) & 1) && ((type[tb]>>1) & 1))mark = true;
}
return mark;
} void dfs(int x,int y){
if(visit[x][y])return;
visit[x][y] = 1;
int tx,ty,i;
for(i=0;i<4;++i){
tx = x + dirx[i];
ty = y + diry[i];
if(yes(x,y,tx,ty,i)){
dfs(tx,ty);
}
}
} int main(){
//freopen("in.txt","r",stdin);
int i,j,ans;
while(scanf("%d %d",&n,&m)!=EOF){
if(n==-1 && m==-1)break;
ans = 0;
memset(visit,0,sizeof(visit));
for(i=1;i<=n;++i){
scanf("%s",farm[i]+1);
}
for(i=1;i<=n;++i){
for(j=1;j<=m;++j){
if(visit[i][j])continue;
++ans;
dfs(i,j);
}
}
printf("%d\n",ans);
}
return 0;
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
HDU 1198 Farm Irrigation (并检查集合 和 dfs两种实现)的更多相关文章
- HDU 1198 Farm Irrigation(状态压缩+DFS)
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1198 题目: Farm Irrigation Time Limit: 2000/1000 MS (Ja ...
- hdu.1198.Farm Irrigation(dfs +放大建图)
Farm Irrigation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- HDU 1198 Farm Irrigation(并查集,自己构造连通条件或者dfs)
Farm Irrigation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...
- HDU 1198 Farm Irrigation(并查集+位运算)
Farm Irrigation Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Tot ...
- hdu 1198 Farm Irrigation(深搜dfs || 并查集)
转载请注明出处:viewmode=contents">http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm ...
- HDU 1198 Farm Irrigation (并查集优化,构图)
本题和HDU畅通project类似.仅仅只是畅通project给出了数的连通关系, 而此题须要自己推断连通关系,即两个水管能否够连接到一起,也是本题的难点所在. 记录状态.不断combine(),注意 ...
- hdu 1198 Farm Irrigation(并查集)
题意: Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a ...
- hdu 1198 Farm Irrigation
令人蛋疼的并查集…… 我居然做了大量的枚举,居然过了,我越来越佩服自己了 这个题有些像一个叫做“水管工”的游戏.给你一个m*n的图,每个单位可以有11种选择,然后相邻两个图只有都和对方连接,才判断他们 ...
- 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Collection 接口又有 3 ...
随机推荐
- 【原创】poj ----- 3009 curling 2 解题报告
题目地址: http://poj.org/problem?id=3009 题目内容: Curling 2.0 Time Limit: 1000MS Memory Limit: 65536K Tot ...
- 4pdf
http://www.cnblogs.com/haocool/archive/2013/03/16/2962547.html
- lambda 3
.NET笔记系列:LAMBDA表达式常用写法 这里主要是将数据库中的常用操作用LAMBDA表达式重新表示了下,用法不多,但相对较常用,等有时间了还会扩展,并将查询语句及LINQ到时也一并重新整理下 ...
- 《Linux Device Drivers》 第十七章 网络驱动程序——note
基本介绍 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备 经常使用的文件上的网络接口操作是 ...
- table 谷歌下不出现滚动条
<table> </table> <style> table {overflow-y:scroll;max-height:152px; height:auto;} ...
- T-SQL中default值的使用
今天介绍一下通过T-SQL语句来创建表时使用default的关键字来自动使用默认值,这个关键字和其它的如:identity,primary key ,not null ,unique等不是相同,这里简 ...
- [ACM] poj 3468 A Simple Problem with Integers(段树,为段更新,懒惰的标志)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 55273 ...
- JavaFX它ListView使用
ListView它是通过同一控制非.在JavaFX在.ListView此外,它拥有非常丰富的功能.下列.让我们来看看如何使用ListView. ListView位于javafx.scene.contr ...
- ExtJS4 根据分配不同的树形菜单在不同的角色登录后
继续我的最后.建立cookie后,带他们出去 var userName = Ext.util.Cookies.get('userName'); var userAuthority = Ext.util ...
- yum 安装时错误 Errno 14 Couldn't resolve host 解决办法(转)
在安装mlocate的时候发现一直报错,错误内容大致如下 Downloading Packages:http://mirrors.163.com/centos/6.5/os/i386/Packages ...