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 ...
随机推荐
- 重新想象 Windows 8 Store Apps (4) - 控件之提示控件: ProgressRing; 范围控件: ProgressBar, Slider
原文:重新想象 Windows 8 Store Apps (4) - 控件之提示控件: ProgressRing; 范围控件: ProgressBar, Slider [源码下载] 重新想象 Wind ...
- HTML学习_01
html总结 html是一门标记语言,也就是不经过编译就能直接执行的语言,不像是c/c++/java等等须要转换成二进制码, html是一门最主要的学科,提供了一个框架,提供了各种标签和规则,使得语言 ...
- Mac下改动Android Studio 所用的JDK版本号
Mac下改动Android Studio 所用的JDK版本号 @author ASCE1885 近期项目从Eclipse+Ant构建模式转移到了Android Studio+Gradle构建模式.自然 ...
- 【leetcode列】3Sum
现在的问题是,我开始思考:一是制定了一些,然后设置这个数字,除了里面找到两个数字.最后,计算和.重复,供N的数量,需要N-2周期. 我的问题是如何找到的其他两个数字,其实,我想引用Two Sum内部解 ...
- json2.js参考
json2.js使用參考 json2.js提供了json的序列化和反序列化方法,能够将一个json对象转换成json字符串,也能够将一个json字符串转换成一个json对象. <html> ...
- char *详细指针
我前段时间写的char*和char[]差额.今char*做一个更深入的了解 1:char像指针和其他指针,也定义一个地址,例如int*它定义了一个堆栈,4字节,char*之,现在写一段代码 #incl ...
- C++习题 对象数组求最大值
Description 建立一个对象数组,内放n(<10)个学生的数据(学号.成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出n个学生中成绩最高者,并输出其学号. In ...
- 解决linux看温度是报错No sensors found问题
今日因为同事的linuxserver频繁死机,其型号和配置与我的一致,故此与其对照了一下server的内存使用率.CPU使用率.温度等信息. 在对照温度信息的时候发现无法使用sensors进行温度查看 ...
- iOS开发多线程篇—多线程简介
iOS开发多线程篇-多线程简介 一.进程和线程 1.什么是进程 进程是指在系统中正在执行的一个应用程序 每一个进程之间是独立的.每一个进程均执行在其专用且受保护的内存空间内 比方同一时候打开QQ.Xc ...
- Android - 用Fragments实现动态UI - 使用Android Support Library
Android Support Library提供了一个带有API库的JAR文件来让你可以在使用最新的Android API的同时也也已在早期版本的Android上运行.例如,Support Libr ...