题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5652
题意:
很久以前,中国和印度之间并没有喜马拉雅山相隔,两国的文化交流很频繁。随着喜马拉雅山海拔逐渐增加,两个地区的交流也越来越少,最终没有了来往。
假设当时的地形和我画的一样,蓝色部分代表海洋,而且当时人们还没有发明轮船。黄色部分代表沙漠,而且沙漠上经常有野鬼散步,所以人们不敢到沙漠中行走。黑色的格子表示山峰,这些山峰都无比高大,所以人无法穿过。白色格子代表平原,
人可以在平原上自由行走。人每次可以向相邻的四个格子走动。 此外,我们的考古学家发现还有一些山峰会逐渐形成,通过研究发现,位置在 (x, y)(x,y) (保证该位置之前没有山峰)的地方在 ii 年后出现了山峰。现在给你若干个位置出现山峰的时间,
你可以计算出中国和印度之间的联系最早被彻底切断的时间吗?
输入描述
多组测试数据, 第一行为组数T(T≤10)。每组测试数据第一行包含两个数 N, M (1≤N,M≤500), 表示地图的大小。接下来 NN 行长度为 MM 的 0101 字符串。00代表白色格子,11 代表山峰。接下来有 Q(1≤Q≤N×M) 行,
第 i(1≤i≤Q) 两个整数 (x,y),0≤x<N,0≤y<M 表示在第 ii 年 (x,y) 出现了一座山峰。
输出描述
对于每组测试数据,输出一个数, 表示两国最早失联的时间。如果最终两国之间还有联系则输出 -1。
可以二分所有的时间,找到第一个让上下不连通的那个时间点;时间复杂度较高;
#include <stdio.h> #include <algorithm> #include<string.h> #include<queue> using namespace std; #define MOD 1000000007 #define N 550 typedef long long LL; char G[N][N]; int m, n, x[N*N], y[N*N]; int dir[4][2]= { {1, 0}, {-1,0}, {0, 1}, {0, -1} }; struct node { int x, y; }; int bfs(int x, int y, char Maps[][N]) { node p, q; queue<node> Q; p.x = x, p.y = y; Q.push(p); int vis[N][N]; memset(vis, 0, sizeof(vis)); vis[x][y] = 1; while(Q.size()) { p = Q.front(); Q.pop(); if(p.x == n-1)///可以连通; return 1; for(int i=0; i<4; i++) { q.x = p.x+dir[i][0]; q.y = p.y+dir[i][1]; if(q.x>=0 && q.x<n && q.y>=0 && q.y<m && Maps[q.x][q.y]=='0' && !vis[q.x][q.y]) { vis[q.x][q.y] = 1; Q.push(q); } } } return 0; } int Judge(char Maps[][N]) { for(int i=0; i<m; i++) { if(Maps[0][i]=='0')///枚举所有第一行可以走的点; { if( bfs(0, i, Maps) )///如果可以连通; return 1; } } return 0; } void Init(char Map[][N], int Mid) { memset(Map, 0, sizeof(Map)); for(int i=0; i<n; i++) for(int j=0; j<m; j++) Map[i][j] = G[i][j]; for(int i=1; i<=Mid; i++) Map[x[i]][y[i]] = '1'; } int main() { int T, k; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); for(int i=0; i<n; i++) scanf("%s", G[i]); scanf("%d", &k); for(int i=1; i<=k; i++) scanf("%d %d", &x[i], &y[i]); int L = 1, R = k, Mid = 0; char Map[N][N]; while(L <= R) { Mid = (L+R) / 2; Init(Map, Mid);///重新构造地图,判断第Mid年加上是否连通; if( !Judge(Map) )///不连通; R = Mid - 1; else L = Mid + 1; } if(L > k) L = -1; printf("%d ", L); } return 0; } /* 15 3 4 1100 0001 0000 2 0 3 2 0 */
重新做了下一这道题;发现是可以用并查集做的,时间复杂度相当于O(Q)的一共有n*m个点,
我们可以编号为1-n*m我们把中国的区域地方看成编号0,印度的区域地方看成n*m+1;
然后把所有的山峰放上去,把所有(i,j)位置能到达的点(xi, yi)建立到一个集合中去;
倒着消除山峰,建立集合,当发现0和n*m+1在一个集中时,说明是当前山峰阻止了两国,答案就是当前山峰的年份;
#include<iostream> #include<algorithm> #include<string.h> #include<stdio.h> #include<math.h> using namespace std; #define INF 0x3f3f3f3f #define N 550 #define PI 4*atan(1.0) #define mod 110119 #define met(a, b) memset(a, b, sizeof(a)) typedef long long LL; int f[N*N], n, m, x[N*N], y[N*N]; char G[N][N]; int dir[4][2] = {{-1,0},{1,0},{0,1},{0,-1}}; int Find(int x) { if(x!=f[x]) f[x] = Find(f[x]); return f[x]; } void Union(int a, int b) { int pa = Find(a); int pb = Find(b); if(pa != pb) f[pa] = pb; } int Cul(int X, int Y) { if(Y<0 || Y>=m) return -1; if(X == -1) return 0; if(X == n) return n*m+1; if(G[X][Y] == '1') return -1; return X*m + Y + 1; } int main() { int T, q; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); for(int i=0; i<n; i++) scanf("%s", G[i]); scanf("%d", &q); for(int i=1; i<=q; i++) { scanf("%d %d", &x[i], &y[i]); G[x[i]][y[i]] = '1'; } for(int i=0; i<=n*m+5; i++)///初始化f; f[i] = i; for(int i=0; i<n; i++) for(int j=0; j<m; j++) { if(G[i][j] == '1') continue; int num1 = Cul(i, j);///找到当前点的编号; for(int k=0; k<4; k++)///与相邻的四点建立关系; { int p = i + dir[k][0]; int q = j + dir[k][1]; int num2 = Cul(p, q); if(num2 != -1)///-1代表不能联合; Union(num1, num2); } } for(int i=q; i>0; i--) { G[x[i]][y[i]] = '0';///消除当前山峰;建立联合; int num1 = Cul(x[i], y[i]); for(int k=0; k<4; k++) { int p = x[i] + dir[k][0]; int q = y[i] + dir[k][1]; int num2 = Cul(p, q); if(num2 != -1) Union(num1, num2); } if(Find(0) == Find(m*n+1))///当两点在一个集合中时;找到答案; { printf("%d ", i); break; } } } return 0; }