【题解】 P1283 平板涂色


~先看题目内容:
1. 给出了N的范围 N **< 16** and 0 < x,y < 100
2. 颜色号为**不小于20的整数**

前者明示了我们这题可使用搜索做法

而非常有意思的是题目中并没有给出颜色号的具体数目

同时也说明了**存在存在颜色号1 与 3 却并不存在2的情况**

应该在代码中注意写法_(:зゝ∠)_

------------

不难构建出一个代码结构 用结构体存储各个矩形数据
```cpp
struct node{
int lx, ly, rx, ry, color;
} f[20];
```
下面就要注意一些光看题目想不到的点了

先从样例走起 : Red → Blue → Red

不难发现很多矩形是在拿起刷子进行了标记以后才符合条件  所以在实现代码的过程中应注意循环遍历矩形时一定要**保证无符合条件矩形**时才能退出

剪枝问题:
- 目前次数超过已确定最小次数则退出
- 同一层某一矩形颜色如果曾被使用无必要重复计算

可行性问题:
- 当矩形位于顶端时可进行填涂
- 当矩形上端**全部**填涂完毕可进行填涂


------------

然后便是一些我个人在做题的一些思路,仅供参考:
1. 为了避免dfs函数过于繁杂  将判断内容写到另一个函数中助于理清思路。
2. 判断是否填涂该矩形是否合法内容必须严谨。
3. 建立布尔型二维矩阵用于判断矩形合法性。
4. 在每一层dfs函数中建立布尔型数组判断改颜色是否被使用过。
5. 注意拿起了刷子是否合法 如果拿起刷子而未填涂则为不合法的。
6. ~~将题目中的x和y轴调换位置~~(个人习惯)

大致的建立一个模型并不难 主要考验一个调试能力

如果读者没有这种能力建议打开输出语句进行观察

本人AC代码:
~~22ms(勉勉强强)~~

------------

```cpp
#include
#include
#include
#include
using namespace std;
struct node{int lx, ly, rx, ry, color;} f[20];
int n, minn = 99999, nofc[20], tot; //别忘了给minn赋初值 tot存储已经填涂矩形数量
bool bol[20], bolmap[20][20];  //前者存储矩形使用情况 后者存储二维矩阵
bool cmp(node a, node b)
{return a.lx < b.lx;}
void dfs(int);
void paint(int color, int num)
{
    //printf("NOW IS %d %d\n", color, num);
    int l = 0, ind[20];  //ind数组存储符合条件矩形的下标 方便进行回溯
    bool flag = true, pp, flag2 = false; //flag用于判断是否还不存有符合填涂条件的矩形
    //pp 用于判断该矩形是否合法 flag2用于判断是否填涂了矩形 若为真进行下一层dfs
    while (flag){
        flag = false;
        for (int i = 0; i < n; ++i){
          if (!bol[i] and f[i].color == color){
              //printf("%d %d %d %d\n", tot, f[i].color, f[i].lx, f[i].ly);  //调试观察
            if (f[i].lx == 0){
              pp = true;}
              else {pp = false;}
              if (!pp) {pp = true;
              for (int j = f[i].ly; j <= f[i].ry; ++j)
                if (!bolmap[f[i].lx][j]) pp = false;}  //对矩形是否合法进行判断
              if (pp){
                  flag = flag2 = true;
                  tot++;
                  bol[i] = true;
                  ind[l++] = i;
                  //printf("paint : tot:%d color:%d lx:%d ly:%d i:%d\n", tot, f[i].color, f[i].lx, f[i].ly, i);
                  //输出合法矩形的各方面信息方便进行检查
                  for (int j = f[i].ly; j <= f[i].ry; ++j)
                    bolmap[f[i].rx][j] = true;
              }
          }
        }
    }
    /*for (int i = 0; i < l; ++i)
        printf("%d ", ind[i]);
    cout << endl;*/ //对ind数组的检查
    if (flag2) dfs(num); // 如果进行了填涂则这次拿起刷子是合法的进行dfs
    //getchar();getchar();
    for (int i = 0; i < l; ++i){
        tot--;
        bol[ind[i]] = false;
        //printf("clean : tot:%d color:%d lx:%d ly:%d i:%d\n", tot, f[ind[i]].color, f[ind[i]].lx, f[ind[i]].ly, ind[i]);
        for (int j = f[ind[i]].ly; j <= f[ind[i]].ry; ++j){
            bolmap[f[ind[i]].rx][j] = false;
        }
    } //利用之前所存的ind数组进行回溯
}
void dfs(int num)
{
    if (num > minn) return;  //最优性剪枝
    if (tot == n){
        minn = min(minn, num);
        return;
    }
    bool bolcolor[20];
    memset(bolcolor, 0, sizeof(bolcolor)); //意义不明
    for (int i = 0; i < n; ++i){
        if (!bol[i] and !bolcolor[f[i].color]){ //保证该矩形与该颜色都没被用过
            paint(f[i].color, num+1);
            bolcolor[f[i].color] = true;
        }
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d %d %d %d %d", &f[i].lx, &f[i].ly, &f[i].rx, &f[i].ry, &f[i].color);
    sort(f, f+n, cmp);
    /*for (int i = 0; i < n; ++i){
        printf("\n%d %d %d %d %d\n", f[i].lx, f[i].ly, f[i].rx, f[i].ry, f[i].color);
    }*/
    //getchar();getchar(); //检查
    dfs(0);
    printf("%d", minn);
}
```

谢谢阅读

转载于:https://www.cnblogs.com/NHDR233/p/11246722.html

你可能感兴趣的:(数据结构与算法)