【HDU5652 BestCoder Round 77 (div1) B】【并查集 or 二分答案BFS】India and China Origins 两国中间出现山脉 最早时间断绝联系

India and China Origins

 
 Accepts: 97
 
 Submissions: 351
 Time Limit: 2000/2000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
很久以前,中国和印度之间并没有喜马拉雅山相隔,两国的文化交流很频繁。随着喜马拉雅山海拔逐渐增加,两个地区的交流也越来越少,最终没有了来往。




假设当时的地形和我画的一样,蓝色部分代表海洋,而且当时人们还没有发明轮船。黄色部分代表沙漠,而且沙漠上经常有野鬼散步,所以人们不敢到沙漠中行走。黑色的格子表示山峰,这些山峰都无比高大,所以人无法穿过。白色格子代表平原,人可以在平原上自由行走。人每次可以向相邻的四个格子走动。

此外,我们的考古学家发现还有一些山峰会逐渐形成,通过研究发现,位置在 (x, y)(x,y) (保证该位置之前没有山峰)的地方在 ii 年后出现了山峰。现在给你若干个位置出现山峰的时间,你可以计算出中国和印度之间的联系最早被彻底切断的时间吗?
输入描述
多组测试数据, 第一行为组数T(T\leq 10)T(T10)。每组测试数据第一行包含两个数 N, M (1 \leq N, M \leq 500)N,M(1N,M500), 表示地图的大小。接下来 NN 行长度为 MM0101 字符串。00代表白色格子,11 代表山峰。接下来有 Q(1\leq Q \leq N\times M)Q(1QN×M) 行,第 i(1\leq i \leq Q)i(1iQ) 两个整数 (x,y),0 \leq x < N, 0 \leq y < M(x,y),0x<N,0y<M 表示在第 ii(x,y)(x,y) 出现了一座山峰。
输出描述
对于每组测试数据,输出一个数, 表示两国最早失联的时间。如果最终两国之间还有联系则输出 -1
输入样例
1
4 6
011010
000010
100001
001000
7
0 3
1 5
1 3
0 0
1 2
2 4
2 1
输出样例
4
Hint
从上图可以看到,两国在第四年彻底失去了联系。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template inline void gmin(T1 &a, T2 b) { if (b 1e5)
	{
		int pause = 1;
	}
	return f[x] == x ? x : f[x] = find(f[x], dep + 1);
}
void merge(int o1, int y, int x)
{
	if (y < 0 || y == n || x < 0 || x == m)return;
	if (s[y][x] != '1')return;
	int o2 = y*m + x;
	o1 = find(o1);
	o2 = find(o2);
	//if (o1 != o2)f[o2] = o1;	//这么写就会被制造出来的数据卡爆栈
	if (o1 != o2)f[o1] = o2;
}
void MERGE(int i, int j)
{
	int o = i*m + j;
	for (int k = 0; k < 8; ++k)merge(o, i + dy[k], j + dx[k]);
	if (j == 0)
	{
		o = find(o);
		lft = find(lft);
		if (o != lft)f[o] = lft;
	}
	if (j == m - 1)
	{
		o = find(o);
		rgt = find(rgt);
		if (o != rgt)f[o] = rgt;
	}
}
vector< pair >b;
void datamaker()
{
	freopen("c://test//input.in", "w", stdout);
	puts("1");
	int n = 500, m = 500;
	printf("%d %d\n", n, m);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)s[i][j] = '0';
		puts(s[i]);
	}
	b.clear();
	for (int i = 0; i < n; ++i)
	{
		if (i % 4 == 0)
		{
			for (int j = 1; j <= m - 2; ++j)b.push_back(MP(i, j));
		}
		else if (i % 4 == 1)
		{
			b.push_back(MP(i, m - 2));
		}
		else if (i % 4 == 2)
		{
			for (int j = m - 2; j >= 1; --j)b.push_back(MP(i, j));
		}
		else
		{
			b.push_back(MP(i, 1));
		}
	}
	b.push_back(MP(n - 1, 0));
	b.push_back(MP(0, m - 1));
	int num = b.size();
	printf("%d\n", num);
	for (int i = 0; i < num; ++i)printf("%d %d\n", b[i].first, b[i].second);
}
int main()
{
	//datamaker(); return 0;
	fre();
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		scanf("%d%d", &n, &m);
		lft = n*m;
		rgt = n*m + 1;
		for (int i = 0; i <= rgt; ++i)f[i] = i;
		for (int i = 0; i < n; ++i)scanf("%s", s[i]);
		for (int i = 0; i < n; ++i)
		{
			for (int j = 0; j < m; ++j)
			{
				if (s[i][j] == '1')MERGE(i, j);
			}
		}
		scanf("%d", &g);
		for (int i = 1; i <= g; ++i)scanf("%d%d", &yy[i], &xx[i]);
		if (find(lft) == find(rgt))
		{
			puts("0");
			continue;
		}
		int ans = -1; 
		for (int tim= 1; tim <= g; ++tim)
		{
			int i = yy[tim];
			int j = xx[tim];
			s[i][j] = '1'; 
			MERGE(i, j);
			if (find(lft) == find(rgt))
			{
				ans = tim;
				break;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
/*
【trick&&吐槽】
错误更可能是逻辑错误,检查自己的考虑是否完备!
错误更可能是逻辑错误,检查自己的考虑是否完备!
错误更可能是逻辑错误,检查自己的考虑是否完备!
1,需要做8个方向的并查集操作。
2,要尽可能写的过程化,函数化,规范化。
3,BC会爆栈,我们考虑一下并查集在什么情况下会爆栈:
	如果我们合并是往新的点上合并,那么对于一个蛇行的图,就会GG
4,二分答案BFS其实可以卡得接近TLE

【题意】
给你一个n*m的棋盘
问你经过多久,棋盘无法从第0行出发到达第n+1行

【类型】
并查集or二分答案bfs

【分析】
只要到达棋盘左右相连的时刻即可
什么时候棋盘左右相连呢?
并查集即可。

*/


你可能感兴趣的:(题库-HDU,数据结构-并查集,二分)