poj 2843 Cutting Cake

題意:一塊N*N大的蛋糕M次訊問,每次切走一個矩形,問每次切的矩形被分成了多少塊(1 <= N <= 1000, 1 <= M <= 10000)。

解法:顯然是求某個區域內的連通分量數目,由於這個區域內的元素在訪問後會被切除,因此每個元素只被訪問一次,因此可以通過dfs或bfs求得某個區域內的連通分量的個數,均攤複雜度。

但是每次尋找遍歷的起始點(即區域內未被切走的蛋糕)複雜度爲O(N^2),因此需要優化,最壞情況是怎麼產生的呢?當某個區域內有連續的已經切走的蛋糕,那我們在尋找未切走的蛋糕時需要逐一判斷,產生複雜度,因此如果遇到連續的切走的區間,如果能夠在短時間內跳過它,那麼複雜度就可以得到控制。類似於supermarket的那個題目,查詢未被佔用的最左元素,我們用並查集維護。對於每一行維護一個並查集,f[x]代表x開始連續的被切走的蛋糕的最右邊的那塊,當某塊蛋糕杯切走且它右邊相鄰的也被切走,就將他合併到右邊的元素,這樣每次查詢尋找遍歷起點的複雜度就變爲O(N)。

注:dfs會爆棧,顯然應該使用bfs

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class CutingCake2843 {
	class Union {
		int f[];
		Union(int n) {
			f= new int[n+10];
			for (int i = 1; i <= n; i++)
				f[i] = i;
		}
		int find(int x) {
			if (x != f[x])
				f[x] = find(f[x]);
			return f[x];
		}
	}
	class node{
		int x,y;
		node(int x,int y){
			this.x=x;
			this.y=y;
		}
	}
	node stack[]=new node[1010*1010];
	boolean vis[][]=new boolean[1010][1010];
	int minx, miny, maxx, maxy, n,top;
	boolean test(int x,int y){
		if (x <minx|| x>maxx||y<miny||y>maxy)
			return false;
		if (vis[x][y])
			return false;
		stack[top++]=new node(x,y);
		vis[x][y]=true;
		return true;
	}
	void bfs(int x, int y) {
		top=0;
		stack[top++]=new node(x,y);
		while(top!=0){
			x=stack[--top].x;
			y=stack[top].y;
		    vis[x][y] = true;
		    if(vis[x][y+1])
			   set[x].f[y]=y+1;
		    if(vis[x][y-1])
			   set[x].f[y-1]=y;
		   test(x,y+1);		    	
		   test(x,y-1);		    	
		   test(x-1,y);		    	
		   test(x+1,y); 
		}
	}

	StreamTokenizer in = new StreamTokenizer(new BufferedReader(
			new InputStreamReader(System.in)));
	int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}
	Union set[] = new Union[1010];
	void run() throws IOException {
		n = nextInt();
		int m = nextInt();
		for (int i = 1; i <= n; i++)
			set[i] = new Union(n);
		while (m-- > 0) {
			minx = nextInt();
			miny = nextInt();
			maxx = nextInt();
			maxy = nextInt();
			int res = 0;
			for (int i = minx; i <= maxx; i++)
				for (int j = miny; j <= maxy;j = set[i].find(j)+1)
					if (!vis[i][j]) {
						bfs(i, j);
						res++;
					}
			System.out.println(res);
		}
	}
	public static void main(String[] args) throws IOException {
		new CutingCake2843().run();

	}

}


發佈了75 篇原創文章 · 獲贊 15 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章