Skip to main content
  1. Posts/

bc #77 ||hdu 5652 India and China Origins (图的动态连通性问题,并查集or 二分+bfs验证连通性)

Note: This article is available in Chinese only. 本文暂无英文版本。 View original

题目链接 题意:没图不好描述,有中文题面中文题面,直接看吧。 思路:据说这道题有三种做法。 当时比赛一种都不会。

先说一种:做法是把格子看成点,可以到达的相邻格子之间看成有边相连,然后倒过来用并查集判断无向图的连通性。具体做法是:先统计初始所有空的位置,然后把所有要增加的山都加上(先统计空的位置是因为山之后要去掉,而去掉以后要得到该点的标号),然后将把所有空的点以及china(设标号为n*m+1)点,和india(**设标号为n*m+2) **点通过并查集来合并..可以从上往下从左往右,每次只需要判断上面的点和左边的点是否有空,如果有就用并查集合并。 china点和india点特殊搞就好。

然后判断india和china是否联通,如果是则输出-1.否则从最后添加的山开始移除,每次移除一座山,添加四个方向能添加的边(注意这里不要忘记如果改点在第0行或者第n-1行还要添加和china或者india的边)

然后移除后询问india和china是否联通 (root(china)==root(india)?)

如果时间i联通了,而i+1没有联通,说明时间i是两国最早的失去联系的时间。

第一次做这种题目,这种题目的一般做法都是倒过来做。貌似还有一个二分删除的山+bfs判断连通性的。。。? 窝再搞搞看。 update :二分+bfs判断连通性。其实这个思路更常规。。做法就是字面意思。注意无解的判断即可。

并查集解法:

  1/* ***********************************************
  2Author :111qqz
  3Created Time :2016年03月27日 星期日 20时11分02秒
  4File Name :code/bc/#77/1003.cpp
  5************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int N=505;
 34char maze[N][N];
 35int f[N*N];
 36int n,m;
 37int q;
 38int p[N][N];
 39int china;
 40int india;
 41struct node
 42{
 43    int x,y;
 44    int id;
 45
 46}shan[N*N],kong[N*N];
 47
 48int root ( int x)
 49{
 50    if (x!=f[x]) f[x] = root (f[x]);
 51    return f[x];
 52}
 53
 54void merge( int x,int y)
 55{
 56    int rx = root (x);
 57    int ry = root (y);
 58//    cout<<"rx::"<<rx<<"   ry::"<<ry<<endl;
 59    if (rx!=ry)
 60    {
 61	f[rx] = ry ;
 62//	f[ry] = rx;
 63    }
 64}
 65
 66void addegg( int x,int y)
 67{
 68    if (x-1>=0&&maze[x-1][y]=='0') merge(p[x][y],p[x-1][y]);
 69    if (x+1<n&&maze[x+1][y]=='0') merge(p[x][y],p[x+1][y]);
 70    if (y-1>=0&&maze[x][y-1]=='0') merge(p[x][y],p[x][y-1]);
 71    if (y+1<m&&maze[x][y+1]=='0') merge(p[x][y],p[x][y+1]);
 72
 73    if (x==0) merge(p[x][y],china);  //一开始忘记更新边缘的山被移除后,点和china以及india的边了。
 74    if (x==n-1) merge(p[x][y],india);
 75}
 76int main()
 77{
 78	#ifndef  ONLINE_JUDGE
 79	freopen("code/in.txt","r",stdin);
 80  #endif
 81
 82	int T;
 83	cin>>T;
 84	while (T--)
 85	{
 86	    scanf("%d %d",&n,&m);
 87	    for ( int i = 0 ; i < n ; i++) scanf("%s",maze[i]);
 88
 89	    scanf("%d",&q);
 90	    for ( int i = 1 ; i <= q ; i++)
 91	    {
 92		int x,y;
 93		scanf("%d %d",&x,&y);
 94		shan[i].x = x;
 95		shan[i].y = y;
 96		shan[i].id = i;
 97//		maze[x][y] = '1';  //先统计空位。
 98	    }
 99
100	    int cnt = 0 ;
101	    ms(p,-1);
102	    for ( int i = 0 ; i  < n ; i++)
103	    {
104		for ( int j = 0 ; j < m;  j++)
105		{
106		    if (maze[i][j]=='0')
107		    {
108			cnt++;
109			kong[cnt].x = i ;
110			kong[cnt].y = j;
111			kong[cnt].id = i;
112			p[i][j] = cnt;
113		    }
114		}
115	    }
116
117	    for ( int i  = 1 ; i <= q ; i ++)
118	    {
119		int x = shan[i].x;
120		int y = shan[i].y;
121		maze[x][y]='1';
122	    }
123	    //check kong...ok!
124	    //for ( int i = 1 ; i  <= cnt ; i++) cout<<"kong:"<<kong[i].x<<" "<<kong[i].y<<endl;
125
126	        china = n*m+1;
127	        india = n*m+2;
128	    for ( int i = 0 ; i <= n*m+2 ; i++) f[i] =  i;
129	//    f[china] = china;
130	  //  f[india] = india;
131	 //   cout<<"china:"<<china<<endl;
132	   // cout<<"india:"<<india<<endl;
133	    for ( int j = 0 ; j  < m ; j++)
134	    {
135		if (maze[0][j]=='0')
136		{
137		    merge(china,p[0][j]);
138		}
139		if (maze[n-1][j]=='0')
140		{
141		    merge(india,p[n-1][j]);
142		}
143	    }
144
145	    for ( int i = 0 ;i < n ; i++)
146	    {
147		for ( int j = 0 ; j < m ; j ++)
148		{
149		    if (maze[i][j]=='1') continue;
150		    if (maze[i-1][j]=='0') merge(p[i-1][j],p[i][j]);
151		    if (maze[i][j-1]=='0') merge(p[i][j-1],p[i][j]);
152		}
153	    }
154
155	    if (root(china)==root(india))
156	    {
157		puts("-1");
158		continue;
159	    }
160
161	    for ( int i = q ; i >= 1 ; i--)
162	    {
163		int x = shan[i].x;
164		int y = shan[i].y;
165
166		maze[x][y] = '0';
167		addegg(x,y);
168		if (root(china)==root(india))
169		{
170		    printf("%d\n",i);
171		    break;
172		}
173	    }
174	}
175
176  #ifndef ONLINE_JUDGE
177  fclose(stdin);
178  #endif
179    return 0;
180}

二分+bfs判断连通性。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :2016年03月28日 星期一 21时12分05秒
  4File Name :code/hdu/5652.cpp
  5************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int N=501;
 34char maze[N][N];
 35int n,m;
 36int q;
 37bool vis[N][N];
 38
 39struct node
 40{
 41    int x,y;
 42
 43    bool ok ()
 44    {
 45	if (x>=0&&x<n&&y>=0&&y<m&&!vis[x][y]) return true;
 46	return false;
 47    }
 48}shan[250005];
 49
 50
 51int check( int id)
 52{
 53
 54    for ( int i = 0 ; i < n ; i++)
 55    {
 56	for ( int j = 0 ; j < m ; j ++)
 57	{
 58	    if (maze[i][j]=='1') vis[i][j] = true;
 59		else vis[i][j] = false;
 60	}
 61    }
 62
 63    for ( int i = 1 ; i <= id ; i++)
 64    {
 65	int x = shan[i].x;
 66	int y = shan[i].y;
 67	vis[x][y] = true;
 68    }
 69
 70    queue<node>q;
 71    for ( int j = 0 ; j  < m ; j++)
 72    {
 73
 74	if (!vis[0][j])
 75	{
 76	    node tmp;
 77	    tmp.x = 0;
 78	    tmp.y = j;
 79	    q.push(tmp);
 80	}
 81    }
 82
 83    while (!q.empty())
 84    {
 85	node pre = q.front();q.pop();
 86	if (pre.x==n-1) return 1;
 87	for ( int i = 0 ; i < 4 ; i++)
 88	{
 89	    node nxt;
 90	    nxt.x = pre.x + dx4[i];
 91	    nxt.y = pre.y + dy4[i];
 92	    if (nxt.ok())
 93	    {
 94		vis[nxt.x][nxt.y] = true;
 95		q.push(nxt);
 96
 97	    }
 98	}
 99    }
100    return 0;
101}
102
103int bin()
104{
105    int l = 1 ;
106    int r = q ;
107    int mid;
108    while (l<=r)
109    {
110	mid = (l+r)/2;
111	if (check(mid))
112	    l = mid + 1;
113	else r = mid -1;
114    }
115    if (l>q) return -1;
116    return l;
117}
118int main()
119{
120	#ifndef  ONLINE_JUDGE
121	freopen("code/in.txt","r",stdin);
122  #endif
123
124	int T;
125	cin>>T;
126	while (T--)
127	{
128	    scanf("%d%d",&n,&m);
129	    for ( int i = 0 ; i  < n;  i++) scanf("%s",maze[i]);
130	    scanf("%d",&q);
131	    for ( int i = 1 ; i <= q ; i ++) scanf("%d %d",&shan[i].x,&shan[i].y);
132	    int ans = bin();
133	    printf("%d\n",ans);
134	}
135
136  #ifndef ONLINE_JUDGE
137  fclose(stdin);
138  #endif
139    return 0;
140}

Related

bc #73 B || hdu 5631 Rikka with Graph (并查集判断无向图的连通性)

http://acm.hdu.edu.cn/showproblem.php?pid=5631 题意;给出一张n个点n+1(n<=100)条边的无向图,现在删除若干条边(至少一条边),问删完之后图依然联通的方案数。 思路:分析可知,由于只删边,不删点,n个点,最少需要n-1条边才能联通,所以最多删两条边。我们可以暴力枚举删除的两条边(或者一条边) O(n^2)的复杂度完全可以接受。剩下的问题就变成了每次删边之后判断图的连通性。 题解给出的是bfs。。。大概是bfs一遍,然后入队的点数是n就联通? 或者dfs一遍也可以? 也是标记过的点数是n就说明联通? 但是看到排名考前的人都是用到了并查集来判断…比较巧妙。

bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (曼哈顿距离的转化【拆点】+set+并查集)

http://www.lydsy.com/JudgeOnline/problem.php?id=1604 题意:了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1..10^9];Xi,Yi∈整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的: 1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi - xil+IYi - Yil≤C. 2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群. 给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛

hdoj 5606 ||bc #68 div 2 B tree

·2 mins
http://acm.hdu.edu.cn/showproblem.php?pid=5606 题意:一棵树,边权为0或者1,问对于每个点,距离它最近的点(包括自身)的个数是多少。输出将所有点的答案异或后的值。 思路:由于包括自身,自己与自己距离为0,那么最近的点一定也距离为0,所以就是找对于每个点与它相连的边权为0 的点的个数**。建图的时候可以不管边权为1的点。。因为这样的点不会对任何点的答案有贡献。**正解貌似是冰茶几。。我就是dfs搞了下。。找到每一个联通快的点数。。然后把某个联通快的所有点的答案都更新成点的个数。。。

codeforces 22 C. System Administrator

·2 mins
http://codeforces.com/contest/22/problem/C 题意:要求用n个点m条边构造一个不允许有重边的图,满足当去掉点v的时候,剩下的n-1个不联通。如果有答案输出任意,没答案输出-1. 思路:首先如果n个点要联通。。至少有n-1条边,此时为一棵树。但是是不是边越多越好呢?显然是不可以的。满足去掉一个点使得n-1个点不联通的情况为,存在一个点u只和v相连,不和任意任何其他点相连,那么当去掉v点,u点就变成不可到达了。边数最多的情况就是,除了v点以外的n-1个点,每个点的度都是n-2(去掉自身以及u点还有n-2个点),,那么除去u点以外的n-1个点的度数就是(n-1)(n-2),边数则为(n-1)(n-2)/2,再加一条连接u的边,所以图的最大边数为(n-1)*(n-2)/2+1,最小为n-1.

codeforces #333 div 2 C. The Two Routes

·2 mins
http://codeforces.com/problemset/problem/602/C 题意:给出n个城镇,m条双向铁路,对于任意不同的x,y,如果x,y之间没有铁路,那么一定有双向公路。train只能走铁路,bus只能走公路。现在一辆火车和一辆bus同时从1出发,要到达n,处于安全考虑,bus和火车不能同时处在除了n以外的点。bus和train不要求同时到达。任意一段道路的时间花费都是1小时。问最少需要多久使得bus和train都到达n。如果存在某个不能到达,那么输出-1. 思路:n才400.一开始打算先按照rail和road建两个图。这两个图互为补。然后在floyd的时候加以判断。但是马上就发现。。不能同时到达同伙一个点这个条件其实不会影响。。因为按照题意,一定存在一条1到n的路,不是公路就是铁路。那么就让有路的花费1的代价到n,然后剩下的求一个一到n的最短路即可。由于n才400.。最短路怎么搞都行。。我偷懒就用floyd了。