poj1691 Painting A Board

链接:http://poj.org/problem?id=1691

题意:有这样一个面板(如下图),分成大大小小的矩形块。现在要对其上色,每个矩形块上一种颜色,颜色已经预先指定好。

每次对一个矩形区域上色,要求必须在该矩形区域上方的所有矩形区域已经被上色后,才能对该矩形区域上色。如下图:

如果要对F区域上色,则在它上面的区域A、B、C、D必须已经被上色。

又每次上色,选择一种特定眼色的笔刷,例如选择蓝色,对A上色,此时可继续对C上色,无需更改颜色。之后,则只能对B区域上色了,则要选择红色笔刷,

所以笔刷的使用次数加1。如果后续过程中,又要重新选择蓝色笔刷,则笔刷仍加1。

问:所需的最少笔刷个数?

先对面板建图,构建成有向图。

一个矩形区域按数据结构(upx,upy,downx,downy,color—upx表示左上角的纵坐标,

upy表示左上角的横坐标,downx表示右下角的纵坐标,downy表示右下角的横坐标

,color表示该矩形区域需要上的颜色)存储

如果两个矩形上下相连,则对其建立有向边。

上下相连首先意味着 rec[i].downx==rec[j].upx

但光这样还不行,如下图,可能存在以下两种情况不符合条件。即

rec[i].upy>rec[j].downup||rec[i].downy<rec[j].upy

对符合条件的矩形建立有向边map[i][j]=1

同时,还要建立每个矩形块的入度。因为只有当一个矩形块的入度为0的时候,

该矩形块才能被上色。

建完图,再用dfs进行搜索。

通俗的说就是选择当前的矩形区域是否对其涂色,选择涂色是一种,不涂色也是一种。

一句话就是,选,不选,选,不选。。。。。

还是看代码吧。看了别人的思路自己写的。有思路,但是自己写不出来。借鉴了别人的。


#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 20
using namespace std;

struct Rec
{
    int upx,upy;
    int downx,downy;
    int color;
}rec[MAXN];
int n,indegree[MAXN],pick_up;       //pick_up存储最终画笔的使用个数
int map[MAXN][MAXN],vist[MAXN];
void input()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d%d%d%d%d",&rec[i].upx,&rec[i].upy,&rec[i].downx,&rec[i].downy,&rec[i].color);
}
void handle()/*建立有向图*/
{
    pick_up=n;          //设置画笔使用次数初始值为n,即矩形块的个数。每个矩形块用一支新画笔。
    memset(indegree,0,sizeof(indegree));        //记录一个矩形块的入度
    memset(map,0,sizeof(map));                  //存储该有向图
    memset(vist,0,sizeof(vist));                //记录一个矩形块是否已经被上色
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            if(rec[i].downx==rec[j].upx&&!(rec[i].downy<rec[j].upy||rec[i].upy>rec[j].downy))
            {
                map[i][j]=1;
                indegree[j]++;
            }
        }
}

void dfs(int num,int cur_color,int cur_up)//num,以上色的矩形块个数;cur_color,当前画笔的颜色;cur_up,当前使用画笔个数
{
    if(cur_up>pick_up)return;       //如果当前的使用画笔个数已经大于目前为止所存储的画笔使用次数的最小值,则返回
    if(num==n)                      //所有矩形块被上色,更新pick_up
    {
        pick_up=cur_up;
    }
    for(int i=0;i<n;i++)            //遍历每个矩形块
    {
        if(!indegree[i]&&!vist[i])  //如果该矩形块入度为0且未上色
        {
            vist[i]=1;
            for(int j=0;j<n;j++)    //相连矩形块入度减1
                if(map[i][j])
                    indegree[j]--;
            if(rec[i].color==cur_color) //如果当前矩形块需要的颜色和cur_color一致,则无需更改
                dfs(num+1,cur_color,cur_up);
            else
                dfs(num+1,rec[i].color,cur_up+1);//不一致,更改画笔颜色,画笔使用次数加1
            vist[i]=0;                          //回朔,恢复之前的状态
            for(int j=0;j<n;j++)
                if(map[i][j])
                    indegree[j]++;
        }
    }
}
int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        input();
        handle();
        dfs(0,0,0);         //初始值:已上色矩形块个数为0,画笔当前颜色为0,画笔当前使用个数为0
        printf("%d\n",pick_up);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值