zoukankan      html  css  js  c++  java
  • CF31D | Chocolate(模拟+离线操作)

    题目描述

    Bob has a rectangular chocolate bar of the size (W*H) . He introduced a cartesian coordinate system so that the point ((0,0)) corresponds to the lower-left corner of the bar, and the point ((W,H)) corresponds to the upper-right corner. Bob decided to split the bar into pieces by breaking it. Each break is a segment parallel to one of the coordinate axes, which connects the edges of the bar. More formally, each break goes along the line (x=x_{c}) or (y=y_{c}) , where (x_{c}) and (y_{c}) are integers. It should divide one part of the bar into two non-empty parts. After Bob breaks some part into two parts, he breaks the resulting parts separately and independently from each other. Also he doesn't move the parts of the bar. Bob made nn breaks and wrote them down in his notebook in arbitrary order. At the end he got (n+1) parts. Now he wants to calculate their areas. Bob is lazy, so he asks you to do this task.

    输入格式

    The first line contains (3) integers (W) , (H) and (n) ((1<=W,H,n<=100)) — width of the bar, height of the bar and amount of breaks. Each of the following nn lines contains four integers (x_{i,1},y_{i,1},x_{i,2},y_{i,2}) — coordinates of the endpoints of the ii -th break (( 0<=x_{i,1}<=x_{i,2}<=W,0<=y_{i,1}<=y_{i,2}<=H) ,or (x_{i,1}=x_{i,2}),or (y_{i,1}=y_{i,2})Breaks are given in arbitrary order.

    It is guaranteed that the set of breaks is correct, i.e. there is some order of the given breaks that each next break divides exactly one part of the bar into two non-empty parts.

    输出格式

    Output (n+1) numbers — areas of the resulting parts in the increasing order.

    ——————————————————————————————————————————

    题意翻译过来就是在笛卡尔坐标系下有一块长方体巧克力,每次以在巧克力上一条平行于坐标轴的线段进行切割,求 (N) 次切割后的各块面积

    数据范围比较小,不去想套什么数据结构了,可以直接离线操作后模拟。

    (vis[][][]) 数组标记某小格与上、下、左、右方向的小格是否有间隙(它们之前是否有切割痕迹),如果有,则把对应值附为真

    如果是横切,那么会把上下若干个小格分开,即:vis[i][sy-1][0]=vis[i][sy][1]=true;

    如果是竖切,那么会把左右若干个小格分开,即:vis[i][sy-1][0]=vis[i][sy][1]=true;

    这样操作 (N) 次后,再用 (dfs) 进行连通块的染色,扩展过程中如发现间隙则说明无法从此方向联通

    每次 (dfs) 都会得到一个连通块的大小,把这个值存入一个 multiset ,自动排序,直接迭代输出完成

    代码如下

    #include <bits/stdc++.h>
    #define MAXN 107
    using namespace std;
    int w,h,n,cnt,way[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
    bool vis[MAXN][MAXN][4],fl[MAXN][MAXN];
    multiset<int> ans;
    //up 0 down 1 left 2 right 3
    void dfs(int x,int y) {
    	cnt++,fl[x][y]=true;
    	for (int i=0;i<4;i++) {
    		int gx=x+way[i][0],gy=y+way[i][1];
    		if (vis[x][y][i] || fl[gx][gy] || gx>=w || gx<0 || gy>=h || gy<0)
    			continue;
    		dfs(gx,gy);
    	}
    }
    int main() {
    	memset(vis,0,sizeof(vis));
    	memset(fl,0,sizeof(fl));
    	scanf("%d%d%d",&w,&h,&n);
    	for (int i=1;i<=n;i++) {
    		int sx,sy,tx,ty;
    		scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
    		if (sx==tx) {
    			if (sy>ty) swap(sy,ty);	//保证循环顺序 
    			for (int i=sy;i<ty;i++)
    				vis[sx-1][i][3]=vis[sx][i][2]=true;
    		} 
    		else {
    			if (sx>tx) swap(sx,tx); //保证循环顺序 
    			for (int i=sx;i<tx;i++)
    				vis[i][sy-1][0]=vis[i][sy][1]=true; 
    		}
    	}
    	for (int i=0;i<w;i++) {
    		for (int j=0;j<h;j++) {
    			if (!fl[i][j]) cnt=0,dfs(i,j),ans.insert(cnt);
    		}
    	}
    	for (multiset<int>::iterator it=ans.begin();it!=ans.end();++it) 
    		printf("%d ",*it); 
    	return 0;
    } 
    
  • 相关阅读:
    8月7号的练习:HDU 1069&&POJ 1636&&HDU 1031&&HDU 1051&&HDU 1551
    8月8号的线段树:HDU 1754&&POJ 3264&&HDU1166
    8月6号的题目:HDU 1003&& POJ 1050&&HDU 1800&&HDU 2036&& POJ 1088(记忆化搜索)
    HDU 1052
    背包问题九讲:
    一个人的旅行 HDU 2066 &&HDU Today HDU 2112
    8月3号的LCS,LIS,LICS:Longest Ordered Subsequence&&Common Subsequence&&Greatest Common Increasing Subsequence
    那些操蛋的搜索题目:逃离迷宫&&哈密顿绕行世界问题
    C语言栈调用机制初探
    linux0.11改进之四 基于内核栈的进程切换
  • 原文地址:https://www.cnblogs.com/zhwer/p/13161327.html
Copyright © 2011-2022 走看看