题意:

给一个n*m的矩阵作为地图,0为通路,1为阻碍。只能向上下左右四个方向走。每一年会在一个通路上长出一个阻碍,求第几年最上面一行与最下面一行会被隔开。

输入:

首行一个整数t,表示共有t组数据。

每组数据首行两个整数n, m,表示矩阵大小。

接下来输入矩阵。

接下来输入一个整数q,表示一共q年。

接下来q行,第i行为两个整数xi, yi,表示在第i年会在xi, yi长出一个阻碍。数据保证只会在通路上生成阻碍。

输出:

如果在第i年被隔开,则输出i。如果始终无法隔开,则输出-1。

吐槽:

我刚开始一看n和m是500,q是n*m,然后判断数据范围是500^3,然后果断判断暴力bfs能过,直接开干,小数据还真过了T_T,结果终测跪了Orz。后来发现其实数据范围是500^4→_→,也就是n*m*q。觉得二分+bfs能过。结果别人说确实能过。然后我自己写了一下,顺利过了。但二分还是写的不熟,中间出了点小差错=_=。

看题解标程居然是并查集,果断给跪,这么吊的思路也是没谁了,而且实现起来也是非常简单的并查集。直接套模板都可以的那种。亏我还专门搞过一段时间的并查集呢,思路还是不够宽广啊,以后脑洞要更大一点才行。嗯,就这么愉快地决定了。

题解:

  1. 二分+bfs。很好理解,将第一行入队,然后bfs向上下左右瞎jb搜,只要能够搜到最后一行,就表示没有隔开(反之亦然)。二分年限即可。时间复杂度O(n*m*log2(q));
  2. 离线并查集,将所有的q保存下来,然后生成最终地图。然后建立初始并查集,将每个通路和它上下左右四个通路连接,创建两个虚节点s1, t1,将第一行所有点连接到s1,将最后一行所有点连接到t1。然后从第q年往回减阻碍,每减一个阻碍就将这个点与它周围所存在的通路合并,直到将s1和t1合并到同一个集合里。然后输出此时的年限即可。时间复杂度为O(n*m+q)。
 #include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int N = ; struct Node
{
int x, y;
}; int dis[][] = {{, }, {-, }, {, }, {, -}}; //搜索的方向 int t, n, m, q;
char mp[N][N]; //初始地图
char s[N][N]; //每次搜的地图
bool vis[N][N]; //记忆化剪枝
Node ss[N*N]; //记录(离线)生成出阻碍 bool bfs(int x) //bfs瞎jb搜,能隔开返回0,连通则返回1
{
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++) s[i][j] = mp[i][j];
}
for(int i = ; i < x; i++) s[ss[i].x][ss[i].y] = '';
queue<Node> que;
memset(vis, , sizeof(vis));
for(int i = ; i < m; i++)
{
if(s[][i] == '')
{
Node p;
p.x = ;
p.y = i;
que.push(p);
vis[][i] = ;
}
}
while(!que.empty())
{
Node p = que.front();
que.pop();
Node pp;
for(int i = ; i < ; i++)
{
int dx = p.x+dis[i][];
int dy = p.y+dis[i][];
if(dx >= && dx < n && dy >= && dy < m && s[dx][dy] == '' && vis[dx][dy] == )
{
if(dx == n-) return ;
pp.x = dx;
pp.y = dy;
que.push(pp);
vis[dx][dy] = ;
}
}
}
return ;
} void Init()
{
scanf("%d%d", &n, &m);
for(int i = ; i < n; i++)
{
scanf("%s", mp[i]);
}
scanf("%d", &q);
for(int i = ; i < q; i++) scanf("%d%d", &ss[i].x, &ss[i].y);
} void Work()
{
int l = , r = q-;
if(!bfs(l)) //判断初始能否隔开
{
printf("0\n");
return;
}
if(bfs(r)) //判断最终能否隔开
{
printf("-1\n");
return;
}
bool flag;
while(l < r-) //二分年限
{
int lr = (l+r)/;
flag = bfs(lr);
if(flag) l = lr;
else r = lr;
}
printf("%d\n", r);
} int main()
{
scanf("%d", &t);
for(int tm = ; tm <= t; tm++)
{
Init();
Work();
}
return ;
}

二分+bfs

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std; const int N = ; int dis[][] = {{, }, {, -}, {, }, {-, }}; //四个方向搜索 int t;
int n, m;
int q;
char mp[N][N]; //地图
int s[N*N][]; //记录(离线)生成的阻碍
int fm[N*N]; //并查集
int vis[N][N]; //dfs记忆化 int mfind(int x) //并查集查询
{
int fx = x;
while(fx != fm[fx])
{
fx = fm[fx];
}
while(x != fx)
{
int mx = fm[x];
fm[x] = fx;
x = mx;
}
return fx;
} void mmerge(int x, int y) //并查集合并
{
int fx = mfind(x);
int fy = mfind(y);
if(fx != fy) fm[fy] = fx;
} void dfs(int x, int y) //遍历全图
{
int dx, dy;
for(int i = ; i < ; i++)
{
dx = x+dis[i][];
dy = y+dis[i][];
if(dx >= && dx < n && dy >= && dy < m && mp[dx][dy] == '' && !vis[dx][dy])
{
mmerge(x*m+y, dx*m+dy);
vis[dx][dy] = ;
dfs(dx, dy);
}
}
} void Init()
{
scanf("%d%d", &n, &m);
for(int i = ; i < n; i++) scanf("%s", mp[i]);
scanf("%d", &q);
for(int i = ; i < q; i++)
{
scanf("%d%d", &s[i][], &s[i][]);
mp[s[i][]][s[i][]] = '';
}
} void Work()
{ for(int i = ; i < n*m+; i++) fm[i] = i; //并查集预处理
memset(vis, , sizeof(vis)); //记忆化标记
for(int i = ; i < n; i++) //遍历全图,初始化并查集
{
for(int j = ; j < m; j++)
{
if(!vis[i][j] && mp[i][j] == '')
{
vis[i][j] = ;
dfs(i, j);
}
}
} for(int i = ; i < m; i++) //虚节点s1(n*m)与t1(n*m+1)的创建
{
mmerge(n*m, i);
mmerge(n*m+, (n-)*m+i);
}
if(mfind(n*m+) == mfind(n*m)) //始终无法隔开
{
printf("-1\n");
return;
} int p; //第p+1年隔开
bool flag = ; //临时标记,退出循环的判断
for(p = q-; p >= ; p--)
{
int dx, dy;
int xx = s[p][];
int yy = s[p][];
mp[xx][yy] = '';
for(int i = ; i < ; i++)
{
dx = xx+dis[i][];
dy = yy+dis[i][];
if(dx >= && dx < n && dy >= && dy < m && mp[dx][dy] == '')
{
mmerge(dx*m+dy, xx*m+yy);
if(mfind(n*m+) == mfind(n*m))
{
flag = ;
break;
}
}
}
if(flag) break;
}
if(flag) printf("%d\n", p+);
else printf("0\n");
} int main()
{
//freopen("test.in", "r", stdin);
scanf("%d", &t);
for(int tm = ; tm <= t; tm++)
{
Init();
Work();
}
}

并查集

hdu 5652 India and China Origins(二分+bfs || 并查集)BestCoder Round #77 (div.2)的更多相关文章

  1. HDU 5652 India and China Origins(经典并查集)

    特别经典的一个题,还有一种方法就是二分+bfs 题意:空间内n*m个点,每个点是0或者1,0代表此点可以走,1代表不能走.接着经过q年,每年一个坐标表示此点不能走.问哪年开始图上不能出现最上边不能到达 ...

  2. hdu 5652 India and China Origins 二分+bfs

    题目链接 给一个图, 由01组成, 1不能走. 给q个操作, 每个操作将一个点变为1, 问至少多少个操作之后, 图的上方和下方不联通. 二分操作, 然后bfs判联通就好了. #include < ...

  3. HDU 5652 India and China Origins 二分+并查集

    India and China Origins 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5652 Description A long time ...

  4. (hdu)5652 India and China Origins 二分+dfs

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5652 Problem Description A long time ago there ...

  5. HDU 5652 India and China Origins 二分优化+BFS剪枝

    题目大意:给你一个地图0代表可以通过1代表不可以通过.只要能从第一行走到最后一行,那么中国与印度是可以联通的.现在给你q个点,每年风沙会按顺序侵蚀这个点,使改点不可通过.问几年后中国与印度不连通.若一 ...

  6. hdu 5652 India and China Origins 并查集+二分

    India and China Origins Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...

  7. HDU 5652 India and China Origins(并查集)

    India and China Origins Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...

  8. hdu-5652 India and China Origins(二分+bfs判断连通)

    题目链接: India and China Origins Time Limit: 2000/2000 MS (Java/Others)     Memory Limit: 65536/65536 K ...

  9. 并查集(逆序处理):HDU 5652 India and China Origins

    India and China Origins Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...

随机推荐

  1. Linux 用户和组管理

    这是用户和组管理的知识点,不想看文字就看视频吧,还是视频为主,文字为备忘录 视频链接: 项目1用户管理 1.创建一个新用户user01,设置其主目录为/home/user01: #useradd –d ...

  2. Spark记录-Scala记录(基础程序例子)

    import scala.util.control._ object learnning { def main(args:Array[String]):Unit={ val n:Int=10 prin ...

  3. 蓝桥杯 算法训练 单词接龙 _DFS_搜索 字符串比较

    单词接龙 问题描述  单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相 ...

  4. spring框架学习(三)spring与junit整合测试

    package cn.mf.b_test; import javax.annotation.Resource; import org.junit.Test; import org.junit.runn ...

  5. 在C#中使用.NET SDK创建控制

    下载示例工程 - 8 Kb 介绍 在这篇教程中,我将使用.NET架构创建一个简单的时钟控制示例,这个控制是一个显示当前时间的时钟,我将指导读者实现秒针并显示钟点数.文章加亮处是创建这个控制的关键点,读 ...

  6. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

  7. 004_加速国内docker源下载速度

    docker下载慢的不行.国内加速器地址 http://355dbe53.m.daocloud.iohttps://docker.mirrors.ustc.edu.cn https://hub-mir ...

  8. Jenkins与代码上线解决方案

    Jenkins是一个用Java编写的开源的持续集成工具.在与Oracle发生争执后,项目从Hudson项目独立. Jenkins提供了软件开发的持续集成服务.它运行在Servlet容器中(例如Apac ...

  9. Ubuntu下SSH安装

    step: 1.输入命令: sudo apt-get install openssh-server 2.验证sshserver是否启动了,以下两条命令均可 ps -e | grep ssh netst ...

  10. urbuntu12.04 ftp服务器搭建

    1.安装ftp服务器: sudo apt-get install vsftpd 2..配置ftp 修改ftp的配置文件,该文件在/etc目录下,在终端中键入如下命令以打开配置文件: sudo vi / ...