HDU 5652 India and China Origins(并查集)

来源:互联网 发布:手机淘宝怎么玩 编辑:程序博客网 时间:2024/06/11 13:48

题意:

中国和印度之间有一片地方,把这片地方抽象化,于是就可以看成一个N * M矩阵,其中黑色的代表高山不能

走过去,白色的代表平原,可以通行,人每次可以选择往上下左右四个方向移动,但是随着时间的变化某些白色的平原

会变色的高山,从而变为不可通行,题目中给出一个代表地势的图,然后有 Q 次操作,第 i 次操作 代表在第 i 年 

(x, y)处的平原变成了高山,即白色变为了黑色。问中国印度最早彻底断绝的时间,如果在 Q 年后还没有断绝就输出 -1;


思路:

刚开始做的时候一看到图求图的连通性,很自然的用回溯了,这道题用 二分 + 回溯, 二分 + BFS都能做出来,

后面觉得还是并查集好理解点,就用并查集又写了一遍,用并查集的思想是如果上下彻底断绝联系,那么说明从

左到存在一片区域,或者一条线,都是由黑色的方格组成,我们可以在为最左边开辟一个新的节点,最右边也开辟

一个的节点,如果这俩个节点某一时刻在一个集合里面了那么说明就已经彻底断绝了。

我的方法是:题目中给的图下标是(0 -- N - 1, 0 - -M - 1),我在这里用 (1 -- N,1 -- M )来保存这个图,把第 0 列

和第M + 1都初始化为1,代表最右边最左边刚开始就是不能走的,为最左边开辟一个节点为 0 ,为最右边开辟一个节点

N * M +1,图中下标为(i, j)的节点以编号 (i - 1) * M + j 代表,也就是图中的点编号从左到右,从上到下分别为1,

2,3,4,5,6.......N * M,如果(i, j)周围八个方向有一个节点的值为 1 那么就可以把这俩个节点并到一个集合里面,在并

的同时查询 0 号节点和 N * M +1号节点是否在一个集合里面,那就说明左右被黑色的联通,上下被彻底断绝联系。


代码:

<pre name="code" class="cpp">#include <stdio.h>  #include <string.h>  #include <iostream>  using namespace std;    const int MAXN = 500;  int pre[MAXN * MAXN + 7];  int Gra[MAXN + 7][MAXN + 7];  //上下左右以及斜着的八个方向int dirX[] = {-1, -1, -1,  0, 0,  1, 1, 1};  int dirY[] = {-1,  0,  1, -1, 1, -1, 0, 1};  int n, m;  //初始化并查集数组void initPre()  {      for(int i  = 0; i <= n * m + 1; i++)          pre[i] = i;  }  //初始化存放图的数组void initGra()  {      memset(Gra, -1, sizeof(Gra));      for(int i = 1; i <= n; i++)//×î×ó±ßºÍ×îÓÒ±ßÒ»¿ªÊ¼¾ÍÊDz»Á¬Í¨µÄ          Gra[i][0] = Gra[i][m + 1] =  1;  }  //带压缩路径的查找操作int Find(int x)  {      return x == pre[x] ? x : pre[x] = Find(pre[x]);  }  void mix(int x, int y)  {      int fx = Find(x);      int fy = Find(y);      if(fx > fy) pre[fx] = fy;      if(fx < fy) pre[fy] = fx;  }  //把(i,j)点和其八个方向的不能走的地方并到一个集合里面void deal(int i, int j)  {      for(int s = 0; s < 8; s++)      {          int x = i + dirX[s];          int y = j + dirY[s];          if(Gra[x][y] == 1)          {              if(y == 0)          mix(0, (i - 1) * m + j);//最左边            else if(y == m + 1) mix(n * m + 1, (i - 1) * m + j);//最右边              else                mix((x - 1) * m + y, (i - 1) * m + j);          }      }  }    int main()  {      //freopen("in.txt", "r", stdin);      int T;      scanf("%d",&T);      while(T--)      {          scanf("%d%d",&n, &m);          initPre();          initGra();          for(int i = 1; i <= n; i++ ){              for(int j = 1; j <= m; j++)              {                  scanf("%1d",&Gra[i][j]);                  if(Gra[i][j] == 1)                      deal(i , j);                  }          }          int Q;          scanf("%d",&Q);          int flag = 0;//是否彻底断绝          int ans = -1;          if(Find(0) == Find(n * m + 1)){ans = 0; flag = 1; }          for(int i = 1; i <= Q; i++)          {              int x, y;              scanf("%d%d",&x, &y);              Gra[x + 1][y + 1] = 1;              deal(x + 1, y + 1);              if( !flag && Find(0) == Find(n * m + 1)){//如果代表最左边的节点和代表最右边的节点在一个集合里面,说明左右联通了,上下断绝了                ans = i;                  flag = 1;              }              }          printf("%d\n",ans);      }      return 0;  } 






0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 夏季羊长的慢怎么办 1岁吃母乳不吃饭怎么办 5个月宝宝黏妈妈怎么办 九个月宝宝不爱吃饭怎么办 20个月宝宝吐了怎么办 十个月的宝宝消化不好怎么办 两岁宝宝不爱喝水怎么办 两岁宝宝不爱喝水吃饭怎么办 两岁的宝宝不爱喝水怎么办 宝宝不爱吃饭不爱喝水怎么办 一多半宝宝爱喝水 不爱吃饭怎么办 1岁宝宝不爱吃饭喝水怎么办 两岁小宝宝不爱吃饭怎么办 4个月小宝宝咳嗽怎么办 3个月小宝宝咳嗽怎么办 2个月小宝宝咳嗽怎么办 8的岁儿童腿不直怎么办 作业盒子选错年级怎么办 两岁x型腿怎么办 绿萝叶子有水滴怎么办 打游戏变菜了怎么办 车被记号笔画了怎么办 水溶性彩铅受潮了怎么办 马克笔颜色涂深了怎么办 染发膏染眉毛了怎么办 用电容笔画画手有触感怎么办 CAD画图线性数字不居中怎么办 3d立体画笔堵塞怎么办 龋齿树脂填充老化后怎么办 小孩补过的牙疼怎么办 颜料弄到墙纸上怎么办 4岁的宝宝不爱涂色怎么办 oppo手机截图存不到相册怎么办 做的ih5保存不了怎么办 小偷偷东西发现后逃跑了怎么办? 网上有人传迷信诅咒怎么办 颜料粘在衣服上怎么办 家里有小偷撬锁怎么办 在家有人在撬门怎么办 6个月的宝宝腹泻怎么办 六个月大的宝宝拉肚子怎么办