CF31D Chocolate 解题报告 *

10 篇文章 0 订阅
8 篇文章 1 订阅
博客详细介绍了Codeforces上的巧克力切割问题,给出了三种不同的解决方案,包括使用深度优先搜索(DFS)的方法。每种解法均通过了所有测试用例,并附有AC代码示例,展示了如何计算每个被切割部分的面积。
摘要由CSDN通过智能技术生成

CF31D Chocolate 解题报告

1 题目链接

https://codeforces.com/problemset/problem/31/D

2 题目整理

题目 : 巧克力

题目描述

鲍勃有一个长方形的巧克力棒,大小是 W × H W \times H W×H。他引入了笛卡尔坐标系,点 ( 0 , 0 ) (0,0) (0,0)对应于巧克力的左下角,点 ( W , H ) (W, H) (W,H)对应于右上角。他决定把这个巧克力切割开来。每一条裂痕都平行于坐标轴,且可以用两个坐标 ( x a , y a ) , ( x b , y b ) (xa, ya), (xb, yb) (xa,ya),(xb,yb)来表示,这里保证 x a = x b xa = xb xa=xb y a = y b ya = yb ya=yb,一个已经被切过的位置不会再去切。现在他切了 n n n刀,想要知道被分成的每一个部分的面积是多少。

输入格式

第一行三个整数 H , W , n H, W, n H,W,n,分别表示巧克力的宽,巧克力的长,切的刀数。

接下来 n n n行没一行四个整数 x a i , y a i , x b i , y b i xa_i, ya_i, xb_i, yb_i xai,yai,xbi,ybi,分别表示第 i i i刀的起点坐标和重点坐标。

输出格式

一行 n + 1 n+1 n+1个整数,表示按升序排列的面积。

样例输入1
2 2 2
1 0 1 2
0 1 1 1
样例输出1
1 1 2
样例输入2
2 2 3
1 0 1 2
0 1 1 1
1 1 2 1
样例输出2
1 1 1 1
样例输入3
2 4 2
0 1 2 1
0 3 2 3
样例输出3
2 2 4
数据范围

对于 100 % 100\% 100%的数据:

  • 1 ≤ H , W , n ≤ 100 1 \leq H, W, n \leq 100 1H,W,n100
  • 0 ≤ x a i , x b i ≤ W 0 \leq xa_i, xb_i \leq W 0xai,xbiW
  • 0 ≤ y a i , y b i ≤ H 0 \leq ya_i, yb_i \leq H 0yai,ybiH

3 题意分析

3.1 题目大意

有一个 W × H W \times H W×H的平面,现在上面有 n n n条线段,这些线段把一个平面分成了 n − 1 n-1 n1个部分,让你求出每个部分的面积。

3.2 样例分析

如上所述。

4 解法分析

这是一道细节很恶心的并查集 or 搜索的题目。

首先,我们需要通过题意来建图。题目说用线段分开两个格子,那么如果有两个格子被线段分开了,那么就说明这两个格子之间没有直通的路径,否则就可以连接(就这一个部分很难实现,至少我觉得)。通过这一个图,我们可以选择搜索来终结这一道题。我们也可以用并查集来统计连通图的大小。

AC代码

ACCode #001
// From rng_58
// Rating 3084
// reason : 思路清晰,代码简洁,运用了深搜
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
 
using namespace std;
 
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
 
#define INF (1<<29)
 
int X,Y,cnt;
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
bool edge[110][110][4];
bool used[110][110];
 
void dfs(int x, int y){
    int i;
    if(x < 0 || x >= X || y < 0 || y >= Y || used[x][y]) return;
    used[x][y] = true; cnt++;
    REP(i,4) if(!edge[x][y][i]) dfs(x+dx[i],y+dy[i]);
}
 
int main(void){
    int N,x1,y1,x2,y2,i,j;
    
    cin >> X >> Y >> N;
    REP(i,N){
        cin >> x1 >> y1 >> x2 >> y2;
        if(x1 == x2) for(j=y1;j<y2;j++) edge[x1-1][j][0] = edge[x1][j][1] = true;
        if(y1 == y2) for(j=x1;j<x2;j++) edge[j][y1-1][2] = edge[j][y1][3] = true;
    }
    
    vector <int> ans;
    REP(i,X) REP(j,Y) if(!used[i][j]){
        cnt = 0;
        dfs(i,j);
        ans.push_back(cnt);
    }
    
    sort(ans.begin(),ans.end());
    REP(i,N+1){
        cout << ans[i];
        if(i == N) cout << endl; else cout << ' ';
    }
    
    return 0;
}
ACCode #002
// From jiangly
// Rating 3323
// reason : 思路清晰,代码简洁,运用了dfs
#include<bits/stdc++.h>
const int MAXN=100,dx[]={0,0,-1,1},dy[]={-1,1,0,0};
int w,h,n;
bool a[MAXN+5][MAXN+5][4],vis[MAXN+5][MAXN+5];
int tot;
int s[MAXN+5];
int dfs(int x,int y){
	if(vis[x][y])
		return 0;
	vis[x][y]=1;
	int ans=0;
	for(int i=0;i<4;++i){
		int x1=x+dx[i],y1=y+dy[i];
		if(a[x][y][i]||x1<1||y1<1||x1>w||y1>h)
			continue;
		ans+=dfs(x1,y1);
	}
	return ans+1;
}
int main(){
	scanf("%d%d%d",&w,&h,&n);
	for(int i=1;i<=n;++i){
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
			for(int j=y1+1;j<=y2;++j){
				a[x1][j][3]=1;
				a[x1+1][j][2]=1;
			}
		else
			for(int j=x1+1;j<=x2;++j){
				a[j][y1][1]=1;
				a[j][y1+1][0]=1;
			}
	}
	for(int i=1;i<=w;++i)
		for(int j=1;j<=h;++j)
			if(!vis[i][j])
				s[++tot]=dfs(i,j);
	std::sort(s+1,s+tot+1);
	for(int i=1;i<=tot;++i)
		printf("%d ",s[i]);
	return 0;
}
ACCode #003
// From BARBARIANNNNN
// Rating 2214
// reason : 思路清晰,代码简洁,运用了dfs
#include<bits/stdc++.h>
using namespace std;
int n,m,k,cnt;
bool x[105][105],y[105][105];
bool vis[105][105];
void dfs(int i,int j) {
	if(i<1||i>n||j<1||j>m)return;
	if(vis[i][j])return;
	vis[i][j]=true;
	cnt++;
	if(!x[i][j])dfs(i+1,j);
	if(!x[i-1][j])dfs(i-1,j);
	if(!y[j][i])dfs(i,j+1);
	if(!y[j-1][i])dfs(i,j-1);
}
int main() {
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1; i<=k; i++) {
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		if(a==c)for(int j=b+1; j<=d; j++)x[a][j]=true;
		else for(int j=a+1; j<=c; j++)y[b][j]=true;
	}
	priority_queue<int>q;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			if(!vis[i][j]) {
				cnt=0;
				dfs(i,j);
				q.push(-cnt);
			}
		}
	}
	while(!q.empty()) {
		printf("%d ",-q.top());
		q.pop();
	}
	return 0;
}
PS : 真的只有我用了并查集吗??!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值