pku 1691 Painting A Board 状态压缩dp

DFS解法:http://www.cnblogs.com/E-star/archive/2012/08/11/2633842.html

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

题意:

给定一个大矩形,然后给出n个需要染色的小矩形的左上角的坐标,右下角的坐标以及该矩形要染得颜色,每个颜色对应的一把刷子。问将这些小矩形染完规定的颜色之后需要最少的刷子数。

要求:只当该小矩形的上边的矩形都染完色之后,该矩形才能染色,如果同一个刷子被使用多次也要计算进来;

 

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn 17
using namespace std;

const int inf = 99999999;

struct node
{
    int lx,ly;
    int rx,ry;
    int col;
}p[maxn];

int dp[1<<maxn][maxn];
int mp[maxn],n,state;
void init()
{
    memset(mp,0,sizeof(mp));
    int i,j;
    for (i = 0; i < n; ++i)
    {
        for (j = 0; j < n; ++j)
        {
            if (i != j && p[i].ry == p[j].ly && !(p[j].rx < p[i].lx || p[j].lx > p[i].rx))
            {
                mp[j] |= (1<<i);//记录j上边所有的矩形
            }
        }
    }
    //初始化
    for (i = 0; i < state; ++i)
    {
        for (j = 0; j < n; ++j)
        {
            dp[i][j] = inf;
        }
    }
    //初始化上边矩形个数为0的
    for (i = 0; i < n; ++i)
    {
        if (mp[i] == 0) dp[1<<i][i] = 1;
    }
}
void DP()
{
    int i,j,k;

    for (i = 0; i < state; ++i)
    {
        for (j = 0; j < n; ++j)
        {
            if ((i&(1<<j)) == 0 && (i&(mp[j])) == mp[j])//如果i状态里面还不存在j矩形并且j上边的矩形在i这个状态里面都染过色了
            {
                for (k = 0; k < n; ++k)
                {
                    if (i&(1<<k))//i这个状态里面存在k我们才能有他推加入j的情况
                    {
                        if (p[k].col == p[j].col)
                        dp[i + (1<<j)][j] = min(dp[i + (1<<j)][j],dp[i][k]);
                        else
                        dp[i + (1<<j)][j] = min(dp[i + (1<<j)][j],dp[i][k] + 1);
                    }
                }
            }
        }
    }

    int Min = inf;
    for (i = 0; i < n; ++i)
    {
        //printf(">>%d\n",dp[state - 1][i]);
        if (Min > dp[state - 1][i]) Min = dp[state - 1][i];
    }
    printf("%d\n",Min);
}
int main()
{
    //freopen("d.txt","r",stdin);
    int t,i;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        for (i = 0; i < n; ++i)
        scanf("%d%d%d%d%d",&p[i].ly,&p[i].lx,&p[i].ry,&p[i].rx,&p[i].col);
        state = (1<<n);//记录所有状态
        init();
        DP();
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/E-star/archive/2012/08/11/2634010.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值