ペンキの色
問題
情報オリンピックの宣伝のために,長方形のベニヤ板にペンキを塗り看板を制作したい.ベニヤ板には色を塗りたくないところにあらかじめ何枚かの長方形のマスキングテープが貼られている.そこでマスキングテープで区切られた領域ごとに別々の色を使いペンキを塗ることにした.例えば,図 5-1 の場合は 5 色のペンキを使う.
入力としてマスキングテープを貼る位置が与えられた時,使うペンキの色の数を求めるプログラムを作成せよ.ただし,ベニヤ板全体がマスキングテープで覆われることはなく,全てのマスキングテープの辺はベニヤ板のいずれかの辺に平行である.
入力
入力は複数のデータセットからなる.各データセットは以下の形式で与えられる.
1 行目にはベニヤ板の幅 w (1 ≤ w ≤ 1000000 となる整数) と高さ h (1 ≤ h ≤ 1000000 となる整数) がこの順に空白区切りで書かれている.
2 行目にはマスキングテープの数 n (1 ≤ n ≤ 1000 となる整数) が書かれている. 続く 3 行目以降の 2 + i 行目 (1 ≤ i ≤ n) には,i 番目に貼るマスキングテープの左下の座標 (x1 , y1 ) と,右上の座標 (x2 , y2 ) が x1 , y1 , x2 , y2 (0 ≤ x1 < x2 ≤ w, 0 ≤ y1 < y2 ≤ h となる整数) の順に空白区切りで書かれている.
ただし,ベニヤ板の左下の角の座標は (0, 0) で右上の角の座標は (w, h) である. 採点用データのうち, 配点の 30% 分は w ≤ 100, h ≤ 100, n ≤ 100 を満たす.
h, w がともに 0 のとき入力の終了を示す. データセットの数は 20 を超えない.
出力
データセットごとに使うペンキの色数を1行に出力する.
入出力例
次の例は図 5-1 の場合である.
入力例
15 6
10
1 4 5 6
2 1 4 5
1 0 5 1
6 1 7 5
7 5 9 6
7 0 9 2
9 1 10 5
11 0 14 1
12 1 13 5
11 5 14 6
0 0
出力例
5
上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。
题意:给定w*h的网格(1<=w,h<=1000000)在上面添加一个左下角坐标为(x1,y1),右上角坐标为(x2,y2)的长方形,即将该区域涂色,求n次涂色后未被涂色的连通块个数。
解法:由于w,h太大,直接DFS或者BFS是不阔能的,所以自然想到将这些顶点坐标分x,y轴分别离散化,最关键的就是这儿了,考虑对x离散化【y同样处理】可以将x,x+1,x-1丢到vector里,然后排序,unique一下,然后再给这些坐标重新赋值,根据新的n个长方形,给一个最大为3n*3n(挑战上写错了)的数组涂色,然后再用DFS或BFS求一下连通块的个数就完了。至于为什么要把x,x-1,x+1离散化,目的是不改变图的联通性,即联通块个数,可以理解成只是将图压缩了,下面这张图可以帮助理解
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<bitset>
#include<stack>
#include<set>
#include<queue>
#include<map>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
#include<fstream>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define pii pair<int, int>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define all(x) x.begin(),x.end()
#define PER(i,x) for(auto i=x.begin();i!=x.end();i++)
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;
const double eps=1.0e-5;
const int maxn=200000+10;
int w,h,n,xa[1005],xb[1005],ya[1005],yb[1005],dir[4][2]={{-1,0},{0,-1},{0,1},{1,0}};
bool mp[3005][3005];
int lisan(int a[],int b[],int k)
{
vector<int> vec;
per(i,-1,1){
per(j,1,n){
if(a[j]+i>=0&&a[j]+i<=k) vec.pb(a[j]+i);
if(b[j]+i>=0&&b[j]+i<=k) vec.pb(b[j]+i);
}
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
per(i,1,n){
a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin();
b[i]=lower_bound(vec.begin(),vec.end(),b[i])-vec.begin();
}
return vec.size()-2;
}
void get_mp()
{
mem(mp,false);
per(i,1,n){
for(int j=xa[i];j<xb[i];j++){
for(int k=ya[i];k<yb[i];k++){
mp[j][k]=true;
}
}
}
}
void dfs(int a,int b)
{
if(a<0||b<0||a>w||b>h||mp[a][b]) return;
mp[a][b]=true;
per(i,0,3) dfs(a+dir[i][0],b+dir[i][1]);
}
void bfs(int a,int b)
{
queue<pair<int,int> >que;
que.push(make_pair(a,b));
mp[a][b]=true;
while(!que.empty()){
pii p=que.front();
per(i,0,3){
int nxtx=p.first+dir[i][0],nxty=p.second+dir[i][1];
if(nxtx<0||nxty<0||nxtx>w||nxty>h||mp[nxtx][nxty]) continue;
que.push(make_pair(nxtx,nxty));
mp[nxtx][nxty]=true;
}
que.pop();
}
}
void solve()
{
int ans=0;
per(i,0,w){
per(j,0,h){
if(!mp[i][j]){
ans++;
dfs(i,j); //这里可以用DFS也可以用BFS
}
}
}
printf("%d\n",ans);
}
int main()
{
//freopen("C:\\Users\\MAC\\Desktop\\in.txt","r",stdin);
while(~scanf("%d%d",&w,&h)&&w&&h){
scanf("%d",&n);
per(i,1,n) scanf("%d%d%d%d",&xa[i],&ya[i],&xb[i],&yb[i]);
w=lisan(xa,xb,w);
h=lisan(ya,yb,h);
get_mp();
solve();
}
}