POJ1691 Painting A Board ACM解题报告(DFS+构造)难题=。=



大致题意:

墙上有一面黑板,现划分为多个矩形,每个矩形都要涂上一种预设颜色C。

由于涂色时,颜料会向下流,为了避免处于下方的矩形的颜色与上方流下来的颜料发生混合,要求在对矩形i着色时,处于矩形i上方直接相邻位置的全部矩形都必须已填涂颜色。

在填涂颜色a时,若预设颜色为a的矩形均已着色,或暂时不符合着色要求,则更换新刷子,填涂颜色b。

 

注意:

1、  当对矩形i涂色后,发现矩形i下方的矩形j的预设颜色与矩形i一致,且矩形j上方的全部矩形均已涂色,那么j符合填涂条件,可以用 填涂i的刷子对j填涂,而不必更换新刷子。

2、  若颜色a在之前填涂过,后来填涂了颜色b,现在要重新填涂颜色a,还是要启用新刷子,不能使用之前用于填涂颜色a的刷子。

3、  若颜色a在刚才填涂过,现在要继续填涂颜色a,则无需更换新刷子。

4、  矩形着色不能只着色一部分,当确认对矩形i着色后,矩形i的整个区域将被着色。

 

首先要注意输入数据,每个矩形信息的输入顺序是 y x y x c,而不是 x y x y c

若弄反了x y坐标怎样也不会AC的.....

这题主要思路就是把长方形看成点,然后判断上下的长方形是否连通,即上面的长方形的ry=下方的长方形的ly,并且不能错开,得有相连部分,用数组记录他们的连通情况,并且记录每个点的入度。DFS回溯解决。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct rect
{
    int lx,ly,rx,ry,col;
}r[16];
int n,ans,deg[16];//每个长方形的入度,当他上面与几块长方形连接时,就有多少入度,如果上面一块被涂色了,就入度-1,入度为0是就是待涂色
int m[16][16];//表明两个长方形之间的连通情况
int vis[16];//长方形是否着色
void build()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(r[i].ry==r[j].ly&&!(r[i].lx>=r[j].rx||r[i].rx<=r[j].lx))
            {
                m[i][j]=1;
                deg[j]++;
            }
        }
    }
}
void dfs(int dep,int cnt,int color)
{
    if(cnt>=ans) return;//当前情况大于等于最优解,剪枝pass
    if(dep==n)
    {
        ans=cnt;//前面已经pass掉了cnt大于等于ans的情况
        return;
    }
    for(int i=0;i<n;i++)
    {
        if(!deg[i]&&!vis[i])
        {
            vis[i]=1;
            for(int j=0;j<n;j++)
            {
                if(m[i][j]) deg[j]--;
            }
            if(r[i].col==color) dfs(dep+1,cnt,color);
            else dfs(dep+1,cnt+1,r[i].col);//判断完颜色后决定是否换刷子
            for(int j=0;j<n;j++)//回溯到上一个结点。进入下一种情况
            {
                if(m[i][j]) deg[j]++;
            }
            vis[i]=0;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d %d %d %d %d",&r[i].ly,&r[i].lx,&r[i].ry,&r[i].rx,&r[i].col);
        }
        ans=20;
        memset(m,0,sizeof(m));
        memset(deg,0,sizeof(deg));
        memset(vis,0,sizeof(vis));
        build();
        dfs(0,0,0);//第一次拿起刷子也算一次pick-up,所以都从0开始;
        printf("%d\n",ans);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值