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 ...
随机推荐
- Java / Android 基于Http的多线程下载的实现
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/26994463 有个朋友需要个多线程现在的例子,就帮忙实现了,在此分享下~ 先说下 ...
- Maven导入eclipse缺少web-resources目录
导入其它机器的maven项目会出现缺少target/m2e/下的web-resources目录,眼下详细原因不知道, 解决方法是,直接将缺少的web-resources目录复制到项目中,错误解决
- [转载]使用python上传图片到 yeelink
#/bin/env python # -*-coding:utf=8 -*- import os,time,subprocess,shlex import urllib2 def upload_yee ...
- ftp的主动模式(port)与被动模式(PASV) (转)
FTP是仅基于TCP的服务,不支持UDP.与众不同的是FTP使用2个端口,一个数据端口和一个命令端口(也可叫做控制端口).通常来说这两个端口是21(命令端口)和20(数据端口).但FTP工作方式的不同 ...
- Windows PowerShell 简介
Powershell 是运行在windows机器上实现系统和应用程序管理自动化的命令行脚本环境.微软之所以将Powershell 定位为Power,并不是夸大其词,因为它完全支持对象.其可读性,易用性 ...
- Effective C++ 条款44
本节条款的标题是:将与參数无关的代码抽离templates 学习本节条款首先须要明确一件事情,那就是模板实例化的过程会不会反复? 我们来举个样例: #include<iostream> u ...
- Cntlm安装和配置体验
对于那些谁使用NTLM验证网络代理环境(即除了需要设置的代理主机和端口还需要提供一个域用户名和密码)供.通过代理上网头疼.这主要是由于非常大的软件不支持NTLM的代理(比方眼下的GIT就不能支持NTL ...
- zend studio 安装emmet(zen coding)
help->Install New Software 在work with后面点击Add,弹出的对话框中填写信息: Name:随意 Location:http://emmet.io/eclips ...
- .NET 4 并行(多核)编程系列之二 从Task开始
原文:.NET 4 并行(多核)编程系列之二 从Task开始 .NET 4 并行(多核)编程系列之二 从Task开始 前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营. ...
- 又一次认识HTML,CSS,Javascript 之node-webkit 初探
今天我们来系统的.全面的 了解一下前端的一些技术,将有助于我们写出 更优秀的 产品 出来. 什么是HTML? HTML 是用来描写叙述网页的一种语言. HTML 包括一些根节点.子节点,文本节点.属性 ...