P1173 [NOI2016] Grid

Topic Provider Luogu

Difficulty NOI/NOI+/CTSC

History Score 100

topic description

King Flea and King Cricket are playing a game.

They are arranged on a grid of n rows and m columns. Among the cc grids (0 ≤ c ≤ n⋅m), each grid has a cricket, and in the remaining grids, each grid has a flea.

We say that two fleas occupying a grid with a common edge are adjacent.

We say that two fleas are connected if and only if the two fleas are adjacent, or there is another flea that is connected to both fleas.

Now, the cricket king hopes that some (zero, one or more) fleas will be replaced with crickets, so that there will be at least two fleas disconnected after that. [picture]

For example: Figure 1 depicts a case where n=4, m=4, c=2.

In this case, King Cricket can achieve his wish by replacing the two fleas in the second row, second column, and third row, third column with crickets, as shown in the right figure. Also, there is no better solution, but there may be other solutions to replace the two fleas.

You need to first judge whether the wish of the cricket king can be fulfilled. If it can be achieved, you also need to minimize the number of fleas that are replaced.

input format

Each input file contains multiple sets of data.

The first line of the input file has only one integer T, indicating the number of groups of data.

Next, input TT sets of data in sequence, the first line of each set of data contains three integers n, m, c.

Next c lines, each line contains two integers x, y means that the grid in the xth row and the yth column is occupied by a cricket. In each set of data, the same cricket will not be described multiple times.

output format

For each set of data, output a line of answers in turn.

If the wish of the cricket king cannot be fulfilled in this set of data, output -1. Otherwise, output the minimum number of replaced fleas.

Input and output samples

input#1

4
4 4 2
1 1
4 4
2 3 1
1 2
2 2 2
1 1
2 2
1 1 0

Output #1

2
1
0
-1

 

Instructions/Tips

sample explanation

The first set of data is the example in the problem description.

For the second set of data, one flea in the second row and second column can be replaced with a cricket, so that there are two fleas that are not connected, and there is no better solution.

For the third set of data, two fleas are already disconnected initially, so there is no need to replace them.

For the fourth set of data, since there is only one flea at most, no two fleas cannot be disconnected no matter how they are replaced.

data range

For all test points, it is guaranteed that 1≤T≤20. We record ∑c as the sum of all c of its T sets of input data in a certain test point. For all test points, Σc≤105.

For all data, satisfy 1≤n, m≤10^9, 0≤c≤n×m, 1≤x≤n, 1≤y≤m.

The detailed data range of each test point is shown in the table below. The n, m, and c in the table are all for a single input data (not a test point), that is to say, the T groups of data under the same test point all meet the restriction conditions; and ∑c is for a single test point spoken. For readability, the "Test Point" column has been placed in the middle of the table instead of the left.

 Problem-solving ideas:

 Those with crickets are regarded as black spots, and those with fleas are regarded as white spots.

Obviously the answer can only be no solution or 0,1,2.

  • If the graph composed of all four-connected white cells is not connected, the answer is 0.

  • Otherwise, if the graph has cut points, the answer is 1

  • Otherwise, if the graph has no more than two points, there is no solution

  • otherwise 2

The first three cases are obvious, and the last case can be sub-graphs with 33 points and more than 33 points respectively.

So directly building a map and running tarjan can be O(nm).

However, this graph has a lot of points but few vacancies. Consider shrinking it into a graph with O(c) points and sides so that the answer remains unchanged after shrinking.

Consider keeping only the following white points:

  • The difference from the x,yx,y coordinates of at least one of the four corners of the grid \leq2≤2

  • connected with a certain black dot eight

  • On the top or bottom of the grid with at least one black dot in the column

  • On the left or right side of the grid with at least one black dot in the row

Then for all the remaining white dots, if the two white dots are in the same row or column, and there are no other dots in the middle (including the black dots and the remaining white dots), connect one side.

Note that not only four connected edges are built.

For example, the blue grid is the reserved point.

Then I found that the answer of this picture is the same as the answer of the original picture in most cases, but when judging -1, it needs to be specially judged if there are two points in the picture, but the two points have edges but are not four-connected. In this case, there will actually be at least three points in it, and the answer is 1, or you can judge n=1, m=1.

I don't know if it's right, and if it's right, how can I prove it? Anyway, after all the uoj hack data , welcome to continue hacking.

And considering that each black point will only contribute up to 8 points around it, and 4 points on the side, a total of 12 points, so a total of O(c) points.

So the complexity bottleneck lies in the construction of the map, the complexity Θ(clogc)

Standard code:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
const int P=1000117;
const int N=100050;
char rB[1<<21],*rS,*rT;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
int x[N],y[N],G[N*24],to[N*192],nxt[N*192],sz,cnt,pre[N*24],dfsc,n,m,c,tmpx[N*24],tmpy[N*24],ctmp;
bool isok[N*24],iscut[N*24];
struct node{
	int x,y;
	node(){}
	node(int x,int y):x(x),y(y){}
};
queue<node> Q,q;
struct Hash{  //用hash实现map
	int h[P],vx[N*25],vy[N*25],p[N*25],nxt[N*25],sz;
	inline void clear(){
		memset(h,0,sizeof(h));sz=0;
	}
	inline void ins(int x,int y,int id){
		int pos=((ll)(x-1)*n+y-1)%P;
		vx[++sz]=x;vy[sz]=y;p[sz]=id;nxt[sz]=h[pos];h[pos]=sz;
	}
	inline int ask(int x,int y){
		for(int k=h[((ll)(x-1)*n+y-1)%P];k;k=nxt[k])if(vx[k]==x&&vy[k]==y)return p[k];
		return 0;
	}
}h,col,tem;
inline int Abs(int x){return x<0?-x:x;}
inline int Max(int a,int b){return a>b?a:b;}
inline void add(int u,int v){
	to[++sz]=v;nxt[sz]=G[u];G[u]=sz;
	to[++sz]=u;nxt[sz]=G[v];G[v]=sz;
}
inline bool check(){
	int i,j,k,tx,ty;
	for(i=1;i<=n;++i)
		for(j=1;j<=m;++j)if(!h.ask(i,j)){
			for(k=0;k<4;++k)if((tx=i+dx[k])&&tx<=n&&(ty=j+dy[k])&&ty<=m&&!h.ask(tx,ty))return 1;
			return 0;
		}
}
inline void bfs(int sx,int sy,int cl){  //第一次floodfill
	int i,u,v,tx,ty;
	q.push(node(sx,sy));col.ins(sx,sy,cl);
	while(!q.empty()){
		u=q.front().x;v=q.front().y;q.pop();
		for(i=0;i<4;++i)if((tx=u+dx[i])&&tx<=n&&(ty=v+dy[i])&&ty<=m&&h.ask(tx,ty)>0&&!col.ask(tx,ty)){
			col.ins(tx,ty,cl);  //用col来记录所属联通块编号(也成为颜色)
			q.push(node(tx,ty));
		}
	}
}
inline bool bfs2(int sx,int sy){
	int i,u,v,x,y,t;
	q.push(node(sx,sy));tem.ins(sx,sy,-1);
	while(!q.empty()){
		u=q.front().x;v=q.front().y;q.pop();
		for(x=Max(1,u-1);x<=n&&x<=u+1;++x)
			for(y=Max(1,v-1);y<=m&&y<=v+1;++y)if((t=h.ask(x,y))&&!tem.ask(x,y))if(t==-1){
				tem.ins(x,y,-1);  //用tem来防止对障碍结点重复访问
//对跳蚤结点的重复访问最多总共c*8个,不会影响复杂度
				q.push(node(x,y));
			}else{tmpx[++ctmp]=x;tmpy[ctmp]=y;}
	}
	if(ctmp==-1)return 1;
	for(i=1,t=col.ask(tmpx[0],tmpy[0]);i<=ctmp;++i)if(col.ask(tmpx[i],tmpy[i])!=t)return 0;
	return 1;
}
inline bool ncon(){  //判断是否不连通
	int i,u,v,ccl=0;
	col.clear();
	while(!Q.empty()){
		u=Q.front().x;v=Q.front().y;Q.pop();
		if(col.ask(u,v))continue;
		bfs(u,v,++ccl);
	}
	tem.clear();
	for(i=0;i<c;++i)if(!tem.ask(x[i],y[i])){
		ctmp=-1;
		if(!bfs2(x[i],y[i]))return 1;
	}
	return 0;
}
int dfs(int u,int fa){  //dfs求割顶
	int i,v,lowu=pre[u]=++dfsc,lowv,chd=0;
	for(i=G[u];i;i=nxt[i])if((v=to[i])!=fa)if(!pre[v]){
		++chd;
		if((lowv=dfs(v,u))>=pre[u])iscut[u]=1;
		if(lowv<lowu)lowu=lowv;
	}else if(pre[v]<lowu)lowu=pre[v];
	if(!fa&&chd==1)iscut[u]=0;
	return lowu;
}
int main(){
	int T=rd(),i,j,k,l,t,tt,tx,ty;
	bool ok;
	while(T--){
		n=rd();m=rd();c=rd();
		h.clear();
		for(i=0;i<c;++i){
			x[i]=rd();y[i]=rd();
			h.ins(x[i],y[i],-1);
		}
		if((ll)n*m-c<2ll){
			puts("-1");
			continue;
		}
		if((ll)n*m-c==2ll){
			puts(check()?"-1":"0");
			continue;
		}
		memset(G,0,sizeof(G));ok=sz=cnt=dfsc=0;
		memset(pre,0,sizeof(pre));
		memset(iscut,0,sizeof(iscut));
		memset(isok,0,sizeof(isok));
        //建图
		for(i=0;i<c;++i)
			for(j=Max(1,x[i]-2);j<=x[i]+2&&j<=n;++j)
				for(k=Max(1,y[i]-2);k<=y[i]+2&&k<=m;++k)if(!(t=h.ask(j,k))){
					h.ins(j,k,++cnt);Q.push(node(j,k));
					isok[cnt]=Max(Abs(j-x[i]),Abs(k-y[i]))<=1;
					for(l=0;l<4;++l)if((tx=j+dx[l])&&tx<=n&&(ty=k+dy[l])&&ty<=m&&(tt=h.ask(tx,ty))>0)add(cnt,tt);
				}else if(t>0&&Max(Abs(j-x[i]),Abs(k-y[i]))<=1)isok[t]=1;
		if(ncon()){
			puts("0");
			continue;
		}
		if(n==1||m==1){  //一行或一列可以特判
			puts("1");
			continue;
		}
		for(i=1;i<=cnt;++i){
			if(!pre[i])dfs(i,0);
			if(isok[i]&&iscut[i]){
				puts("1");
				ok=1;break;
			}
		}
		if(!ok)puts("2");
	}
	return 0;
}

Via picture:

Thanks for watching! 

Guess you like

Origin blog.csdn.net/asuf1364/article/details/132119859