题目大意:在一个1000000*1000000的矩阵中放入几块木板,问你这些木板把矩阵划分成了几个区域?输入会给左下角和右上角的坐标,输入W==0且H==0结束。
这一题是书上的作业题,书上有一道差不多的例题,但是书上那道例题是用的直线的,而且他的坐标是点格,而这道题是坐标(这个很重要,我一开始没有区分好导致理解不了)。那么这一题肯定要用到坐标压缩的(1000000*1000000太大了,我们可以把木板压缩到最小就可以了),标准的直接看代码就好了,很容易理解。
然后现在这题很难的一个地方在于,怎么高效地判断和填充木板区域,当然我们可以一个一个木板找,然后匹配填充,但是显然这样比较慢(这种操作复杂度是0(W*H*N),虽然坐标压缩了以后这个不会很大,但是还是有其他更好的方法的),这里有一个很神奇的imos法,imos法不仅仅是用来做这种ACM的题的,还是一个很实用的工程算法。
imos法详解(中文版,我还没得到原作者的同意,我就直接贴连接了)http://www.hankcs.com/program/algorithm/imos_method.html
imos法详解(日文原版,这里有上面中文版没有的imos如何应对特殊的三角形矩阵的填充和一些函数(二次函数,高斯函数)的问题)http://imoz.jp/algorithms/imos_method.html
(ps:上面两个的那个影响力计算的图是错的(代码没有错),-1的位置错了。)
最后我们用BFS就可以了(DFS容易爆栈,当然你用栈来模拟我没话说)。
1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 #include <string.h> 5 #include <stdio.h> 6 #include <vector> 7 #include <queue> 8 #define MAX_N 1010 9 10 using namespace std; 11 12 static int X1[1010], Y1[1010], X2[1010], Y2[1010], fld[MAX_N * 2][MAX_N * 2], 13 dx[4] = { -1, 0, 0, 1 }, dy[4] = { 0, -1, 1, 0 }; 14 15 static int compress(int *const, int *const, const int, const int); 16 static int bfs(const int, const int); 17 void imos(const int, const int, const int); 18 19 int main(void) 20 { 21 int W, H, N; 22 23 //freopen("D:\\input.txt", "r", stdin); 24 while (1) 25 { 26 scanf("%d%d", &W, &H); 27 if (W == 0 && H == 0) 28 break; 29 scanf("%d", &N); 30 for (int i = 0; i < N; i++) 31 { 32 scanf("%d%d%d%d", &X1[i], &Y1[i], &X2[i], &Y2[i]); 33 } 34 W = compress(X1, X2, W, N); 35 H = compress(Y1, Y2, H, N); 36 37 imos(W, H, N); 38 cout << bfs(W, H) << endl; 39 } 40 return EXIT_SUCCESS; 41 } 42 43 static int compress(int *const s1, int *const s2, const int W, const int N) 44 { 45 //坐标离散化 46 vector<int>xs; 47 48 for (int i = 0; i < N; i++) 49 { 50 if (0 < s1[i] && s1[i] < W) xs.push_back(s1[i]); 51 if (0 < s2[i] && s2[i] < W) xs.push_back(s2[i]); 52 } 53 xs.push_back(0); 54 xs.push_back(W);//加上边界条件 55 sort(xs.begin(), xs.end()); 56 xs.erase(unique(xs.begin(), xs.end()), xs.end()); 57 58 for (int i = 0; i < N; i++) 59 { 60 s1[i] = find(xs.begin(), xs.end(), s1[i]) - xs.begin(); 61 s2[i] = find(xs.begin(), xs.end(), s2[i]) - xs.begin(); 62 } 63 return xs.size() - 1;//注意这里要获取的边界条件使得size加了2,要减1才能刚好变成真正的数组长度 64 } 65 66 static int bfs(const int W, const int H) 67 { 68 int ans = 0; 69 for (int i = 0; i < W; i++) 70 for (int j = 0; j < H; j++) 71 { 72 if (fld[i][j])continue;//搜索没有挡板的位置 73 ans++; 74 75 queue<pair<int, int> > que; 76 que.push(make_pair(i, j)); 77 while (!que.empty()) 78 { 79 int tx = que.front().first, ty = que.front().second; 80 que.pop(); 81 for (int i = 0; i < 4; i++) 82 { 83 int ttx = tx + dx[i], tty = ty + dy[i]; 84 if (0 <= ttx && ttx <= W 85 && 0 <= tty && tty <= H 86 && !fld[ttx][tty]) 87 { 88 que.push(make_pair(ttx, tty)); 89 fld[ttx][tty] = 1; 90 } 91 } 92 } 93 } 94 return ans; 95 } 96 97 void imos(const int W, const int H, const int N) 98 { 99 //imos法统计区间 100 memset(fld, 0, sizeof(fld)); 101 102 for (int i = 0; i < N; i++)//统计影响力 103 { 104 fld[X1[i]][Y1[i]]++; 105 fld[X1[i]][Y2[i]]--; 106 fld[X2[i]][Y1[i]]--; 107 fld[X2[i]][Y2[i]]++; 108 } 109 for (int i = 0; i < W; i++)//累计横向 110 for (int j = 1; j < H; j++) 111 fld[i][j] += fld[i][j - 1]; 112 113 for (int j = 0; j < H; j++)//累计纵向 114 for (int i = 1; i < W; i++) 115 fld[i][j] += fld[i - 1][j]; 116 //非零部分就是有挡板的位置了 117 }
另外吐槽一下AOJ,编译器是个什么鬼编译器,连queue<pair<int,int>>都要报错,居然不能识别pair<int,int>和queue的>的区分,不过AOJ有input和output文件,这个好评
Greedy:Paint Color(AOJ 0531)
时间: 2024-10-12 11:55:37
Greedy:Paint Color(AOJ 0531)的相关文章
Android中自定义常用的三个对象解析(Paint,Color,Canvas)
Paint,Color,Canvas Paint:画笔对象,画图用的"笔" Color:颜色,相当于调料 Canvas:画布,现实中的纸板 Paint 画笔 常用的方法就是设置和获取到画笔的样式: paint.setStyle(); 设置画笔的风格,空心的或者是实心的 paint.setColor(); 设置画笔的颜色 paint.setStrokeWidth(); 设置边框线的宽度 paint.setAlpha(); 设置画笔的Alpha值 paint.setAntiAlias();
AOJ 0531:Paint Color(二维离散+imos)
[题目链接] http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0531 [题目大意] 给出一张图,和一些矩形障碍物,求该图没被障碍物覆盖的部分被划分为几个连通块 [题解] 首先对图中的点进行离散化,对于一个障碍物来说, 我们将其看做左闭右开上闭下开的图形,所以在离散的时候只要离散障碍物的点即可. 之后我们利用imos积累法得出哪些部分是障碍物,就可以统计连通块了. [代码] #include <cstdio> #include
Android Paint画笔及Color .
引自:http://blog.csdn.net/q445697127/article/details/7736926 Paint paint = new Paint(); // 设置paint为无锯齿 paint.setAntiAlias(true); // 设置颜色 paint.setColor(Color.RED); // 设置颜色 paint.setColor(Color.rgb(255, 0, 0)); // 设置透明度 paint.setAlpha(256); // 提取颜色 Colo
防手机联系人功能的实现
package com.loaderman.contactsrecycledemo; /* * This code is cloned from DefaultItemAnimator provided by support library v7-recyclerView * * Copyright (C) 2014 The Android Open Source Project * Copyright (c) 2014-2015 Gabriele Mariotti. * * Licensed
JavaFX Application应用实例
下面代码演示的是JavaFX进程命令行参数的实例.大家可以参阅一下. /*原文地址:http://www.manongjc.com/article/134.html */ import java.util.List; import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.sce
等价类划分方法及其示例(2)
package threebox; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.layo
SpannableString 你应该知道的那些效果显示
一个人需要隐藏多少秘密才能巧妙地度过一生 - 仓央嘉措 前言 上次看到一款学习的 App,有这样一个功能,在一个 TextView 中有一段英文,点击英文单词通过语音朗读出来.语音先不考虑,怎么去实现 TextView 点击获取每个单词的内容的呢? 肯定是用SpannableString去实现的呗,不然你今天讲它干嘛.嘿嘿,我说的对不对? 答案是肯定的,由于惯性我们先来看看效果图: 我这里没有获取每个单词,而是获取的每段句子.效果图上也展示了一些其他的SpannableString效果,大多数可
冯斌:JavaFx实例(十三)“FontEffect”
本实例演示用JavaFx改变文字的字体,制造文字的阴影和倒影等效果.将会用到如下的三个类: javafx.scene.text.Font javafx.scene.effect.DropShadow javafx.scene.effect.Reflection 本实例的代码如下: import javafx.application.Application; import javafx.scene.layout.Pane; import javafx.scene.Scene; import j
冯斌:JavaFx实例(九)“Text”
在JavaFx中Text类定义了一个node,这个node能显示字符串,如下图所示. 其中点(x,y)是字符串的起点.Text对象通常放在一个pane对象里.Pane对象的左上角坐标是(0,0),右下角的坐标是(pane.getWidth(),pane.getHeight()).多行字符串用\n分割开来. Text类的UML图如下图所示.一个shape就是一个node,Shape类是其他所有图形类的根类. 程序实例清单如下: import javafx.application.Applicati