hdu 5652 India and China Origins(二分+bfs || 并查集)BestCoder Round #77 (div.2)
2016-03-31 22:01
357 查看
题意:
给一个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能过。结果别人说确实能过。然后我自己写了一下,顺利过了。但二分还是写的不熟,中间出了点小差错=_=。
看题解标程居然是并查集,果断给跪,这么吊的思路也是没谁了,而且实现起来也是非常简单的并查集。直接套模板都可以的那种。亏我还专门搞过一段时间的并查集呢,思路还是不够宽广啊,以后脑洞要更大一点才行。嗯,就这么愉快地决定了。
题解:
二分+bfs。很好理解,将第一行入队,然后bfs向上下左右瞎jb搜,只要能够搜到最后一行,就表示没有隔开(反之亦然)。二分年限即可。时间复杂度O(n*m*log2(q));
离线并查集,将所有的q保存下来,然后生成最终地图。然后建立初始并查集,将每个通路和它上下左右四个通路连接,创建两个虚节点s1, t1,将第一行所有点连接到s1,将最后一行所有点连接到t1。然后从第q年往回减阻碍,每减一个阻碍就将这个点与它周围所存在的通路合并,直到将s1和t1合并到同一个集合里。然后输出此时的年限即可。时间复杂度为O(n*m+q)。
并查集
给一个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能过。结果别人说确实能过。然后我自己写了一下,顺利过了。但二分还是写的不熟,中间出了点小差错=_=。
看题解标程居然是并查集,果断给跪,这么吊的思路也是没谁了,而且实现起来也是非常简单的并查集。直接套模板都可以的那种。亏我还专门搞过一段时间的并查集呢,思路还是不够宽广啊,以后脑洞要更大一点才行。嗯,就这么愉快地决定了。
题解:
二分+bfs。很好理解,将第一行入队,然后bfs向上下左右瞎jb搜,只要能够搜到最后一行,就表示没有隔开(反之亦然)。二分年限即可。时间复杂度O(n*m*log2(q));
离线并查集,将所有的q保存下来,然后生成最终地图。然后建立初始并查集,将每个通路和它上下左右四个通路连接,创建两个虚节点s1, t1,将第一行所有点连接到s1,将最后一行所有点连接到t1。然后从第q年往回减阻碍,每减一个阻碍就将这个点与它周围所存在的通路合并,直到将s1和t1合并到同一个集合里。然后输出此时的年限即可。时间复杂度为O(n*m+q)。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int N = 510; int dis[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; //四个方向搜索 int t; int n, m; int q; char mp ; //地图 int s[N*N][2]; //记录(离线)生成的阻碍 int fm[N*N]; //并查集 int vis ; //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 = 0; i < 4; i++) { dx = x+dis[i][0]; dy = y+dis[i][1]; if(dx >= 0 && dx < n && dy >= 0 && dy < m && mp[dx][dy] == '0' && !vis[dx][dy]) { mmerge(x*m+y, dx*m+dy); vis[dx][dy] = 1; dfs(dx, dy); } } } void Init() { scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) scanf("%s", mp[i]); scanf("%d", &q); for(int i = 0; i < q; i++) { scanf("%d%d", &s[i][0], &s[i][1]); mp[s[i][0]][s[i][1]] = '1'; } } void Work() { for(int i = 0; i < n*m+2; i++) fm[i] = i; //并查集预处理 memset(vis, 0, sizeof(vis)); //记忆化标记 for(int i = 0; i < n; i++) //遍历全图,初始化并查集 { for(int j = 0; j < m; j++) { if(!vis[i][j] && mp[i][j] == '0') { vis[i][j] = 1; dfs(i, j); } } } for(int i = 0; i < m; i++) //虚节点s1(n*m)与t1(n*m+1)的创建 { mmerge(n*m, i); mmerge(n*m+1, (n-1)*m+i); } if(mfind(n*m+1) == mfind(n*m)) //始终无法隔开 { printf("-1\n"); return; } int p; //第p+1年隔开 bool flag = 0; //临时标记,退出循环的判断 for(p = q-1; p >= 0; p--) { int dx, dy; int xx = s[p][0]; int yy = s[p][1]; mp[xx][yy] = '0'; for(int i = 0; i < 4; i++) { dx = xx+dis[i][0]; dy = yy+dis[i][1]; if(dx >= 0 && dx < n && dy >= 0 && dy < m && mp[dx][dy] == '0') { mmerge(dx*m+dy, xx*m+yy); if(mfind(n*m+1) == mfind(n*m)) { flag = 1; break; } } } if(flag) break; } if(flag) printf("%d\n", p+1); else printf("0\n"); } int main() { //freopen("test.in", "r", stdin); scanf("%d", &t); for(int tm = 1; tm <= t; tm++) { Init(); Work(); } }
并查集
相关文章推荐
- 160331
- struts2工作流程
- 蘑菇街在线笔试题
- 软考中高项学员:2016年3月28日作业
- 【bzoj2022】弹飞绵羊
- leetcode_154 Find Minimum in Rotated Sorted Array II
- jquery中生成一个带cha的tag
- [C#]UDP通讯
- ZOJ 2736 Daffodil number
- c++中生成n个m位的随机不重复字符串的一种方法(字母+数字)
- Android 的 SDK Manager 无法启动 闪退解决方法
- 解决Attribute "rippleColor" has already been defined的问题
- Code resource ✵1
- 关于HashMap的ContainsKey()
- 移动端position:fixed小结
- 我的第一篇破壳
- UVA 208 Firetruck
- hadoop生态系统学习之路(五)hbase的简单使用
- js 事件监听封装
- Dubbo框架介绍