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 ...
随机推荐
- TCP/IP详细说明--滑模、拥塞窗口、慢启动、Negle算法
TCP的数据流大致能够分为两类,交互数据流与成块的数据流. 交互数据流就是发送控制命令的数据流.比方relogin,telnet.ftp命令等等.成块数据流是用来发送数据的包,网络上大部分的TCP包都 ...
- oracle查询和编写数据字典
在项目交付时假设须要编写数据字典,能够採用以下的方法.首先执行以下的sql语句 SELECT A.TABLE_NAME AS 表名, A.COLUMN_NAME AS 字段名, DECODE(A.CH ...
- 读取 raspberrypi 的cpu和gpu温度
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import json import time import command ...
- ueditor问题解决
ueditor图片无法上传? 解决: imageUp.ashx 去掉这一行 <%@ Assembly Src="Uploader.cs" %> 参考: http://w ...
- 程序员联盟有自己的论坛啦!基于Discuz构建,还不来注册~
我把程序员联盟网站的论坛建好了,哈哈哈.用的是Discuz这个腾讯旗下的中文bbs建设软件.正在完善论坛,添加各种模块和应用.大家可以先去注册一下:coderunity.com/bbs/forum.p ...
- UI 纯代码实现计算器
// MHTAppDelegate.h // TestCa // Copyright (c) 2014年 Summer. All rights reserved. #import <UIK ...
- A simple Test Client built on top of ASP.NET Web API Help Page
Step 1: Install the Test Client package Install the WebApiTestClient package from the NuGet Package ...
- Java AIO 入门实例(转)
Java7 AIO入门实例,首先是服务端实现: 服务端代码 SimpleServer: public class SimpleServer { public SimpleServer(int port ...
- HDOJ 5188 zhx and contest 贪婪+01背包
zhx and contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- [原创].NET 分布式架构开发实战之三 数据访问深入一点的思考
原文:[原创].NET 分布式架构开发实战之三 数据访问深入一点的思考 .NET 分布式架构开发实战之三 数据访问深入一点的思考 前言:首先,感谢园子里的朋友对文章的支持,感谢大家,希望本系列的文章能 ...