poj - 1691 - Painting A Board(状态压缩dp)

题意:N(1 <= N <= 15)个矩形,每个矩形要涂上指定的颜色C(1 <= C <= 20),如果给一个矩形涂色,那么与它相邻的上方矩形必须已经涂色,问最少要取几次画笔。

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

——>>状态:dp[S][color] 表示达到状态 S 且最后一次涂色为 color 时的最小取画笔数

状态转移方程:dp[S][color] = min(dp[S][color], dp[sub][i]); 或者 dp[S][color] = min(dp[S][color], dp[sub][i] + 1);

时间复杂度:O(N * C * 2 ^ N)

#include <cstdio>
#include <algorithm>
#include <cstring>

using std::min;

const int MAX_COLOR = 20;
const int MAX_RECTANGLE = 15;
const int INF = 0x3f3f3f3f;

struct RECTANGLE
{
    int ly;
    int lx;
    int ry;
    int rx;
    int color;
    int fa[MAX_RECTANGLE];
    int cnt;
} r[MAX_RECTANGLE];

int M, N;
int dp[1 << MAX_RECTANGLE][MAX_COLOR + 1];

void Read()
{
    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].color);
        r[i].cnt = 0;
    }
}

void Init()
{
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            if (j != i && r[j].ry == r[i].ly && r[j].rx > r[i].lx && r[j].lx < r[i].rx)
            {
                r[i].fa[r[i].cnt++] = (1 << j);
            }
        }
    }
}

bool IsReady(int x, int S)
{
    for (int i = 0; i < r[x].cnt; ++i)
    {
        if (!(r[x].fa[i] & S))
        {
            return false;
        }
    }

    return true;
}

int Idx(int x)
{
    int i = 0;

    while ((1 << i) != x)
    {
        ++i;
    }

    return i;
}

void Dp()
{
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 1; i <= MAX_COLOR; ++i)
    {
        dp[0][i] = 1;
    }

    for (int S = 1; S <= (1 << N) - 1; ++S)
    {
        for (int t = S; t; t -= t & -t)
        {
            int cur = Idx(t & -t);
            int sub = S & ~(t & -t);
            int color = r[cur].color;

            if (IsReady(cur, sub))
            {
                for (int i = 1; i <= MAX_COLOR; ++i)
                {
                    if (color == i)
                    {
                        dp[S][color] = min(dp[S][color], dp[sub][i]);
                    }
                    else
                    {
                        dp[S][color] = min(dp[S][color], dp[sub][i] + 1);
                    }
                }
            }
        }
    }
}

void Output()
{
    int ret = INF;

    for (int i = 1; i <= 20; ++i)
    {
        ret = min(ret, dp[(1 << N) - 1][i]);
    }

    printf("%d\n", ret);
}

int main()
{
    scanf("%d", &M);
    while (M--)
    {
        Read();
        Init();
        Dp();
        Output();
    }

    return 0;
}
时间: 2024-10-12 08:02:25

poj - 1691 - Painting A Board(状态压缩dp)的相关文章

POJ - 1691 Painting A Board (状态压缩 + 暴力)

题目大意:要将一个大矩形內的所有小矩形涂色,涂色要求,只有该矩形上面的所有矩形都涂色了才可以涂该颜色,换一种填涂的颜色就要花费一点体力值,问填涂完需要花费的最小体力值 解题思路:先处理一下填涂该矩形的前提条件,我用了一个can数组表示填涂该矩形时要满足的状态量 用dp[color][state]表示当前用的颜色是color,填涂的状态为state时所用的最少体力值 然后暴力得出转换和结果 #include<cstdio> #include<cstring> #include<

POJ 1691 Painting A Board(DFS)

链接 题意 : 看了好长时间终于看懂题目了,将一个大矩形划分成若干小矩形,告诉你每个小矩形的左上角那个点和右下角那个点的坐标,告诉你这个小矩形要涂的颜色,每个颜色对应一个刷子,问你最少要使用几次刷子.因为你要刷一个矩形之前,必须把这个矩形上方与之直接相邻的所有矩形先刷掉才能刷这个,如果你先用了红色的刷子,然后又用了蓝色的刷子,最后又用了红色的刷子,这算是3次使用而不是两次,样例中,用红色刷B所以D也可以刷了,用蓝色先刷A,然后可以刷C,因为B刷了所以E也可以刷了,最后换刷子把剩下的刷掉,总共三次

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

POJ 1038 Bugs Integrated, Inc. 状态压缩DP

题目来源:1038 Bugs Integrated, Inc. 题意:最多能放多少个2*3的矩形 思路:状态压缩DP啊 初学 看着大牛的代码搞下来的  总算搞懂了 接下来会更轻松吧 3进制代表前2行的状态(i行和i-1行)1代表i-1行占位 2代表i行占位 i-1不管有没有占位都不会影响的0代表i行和i-1行都空闲 然后枚举状态dfs更新状态 话说就不能没写深搜了 有点不会了 #include <cstdio> #include <cstring> #include <alg

[POJ 2411] Mondriaan&#39;s Dream 状态压缩DP

题意 给定一个 n * m 的矩形. 问有多少种多米诺骨牌覆盖. n, m <= 11 . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define LL long long 7 inline

POJ 1691 Painting A Board

题目大意: 墙上有一块区域被分成了n个矩形,每个矩形要涂上各自的颜色.为了保证完美要求这一块区域可以进行涂色的条件是它上方的所有区域都已经涂好颜色,这样就不会有后续的操作影响这块区域的颜色.但是如果两块区域颜色不同就要换涂颜色用的刷子.问最少需要换几次. 解题思路: 区域涂色的大体次序是由拓扑排序决定的,当有多个区域在同一层次时需要枚举这些区域来保证换刷子的次数最小. 下面是代码: #include <stdio.h> #include <stdlib.h> struct node

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and

POJ 2288 Islands And Bridges 状态压缩dp+哈密顿回路

题意:n个点 m条边的图,路径价值定义为相邻点乘积,若路路径c[i-1]c[i]c[i+1]中c[i-1]-c[i+1]有边 则价值加上三点乘积找到价值最大的哈密顿回路,和相应的方法数n<=13.暴力dfs O(13!) TLE 由于n<13 经典的状态压缩dp [状态] [当前点位置 ][前一点位置] 注意上一个状态必须合法才能进行转移设状态dp[s][i][j] 当前状态为s,当前点为i上一个点为j的最大价值, ans=max(dp[(1<<n)-1][i])dp[s][i][

[poj 1691] Painting A Board dfs+拓扑排序

Painting A Board Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 3611 Accepted: 1795 Description The CE digital company has built an Automatic Painting Machine (APM) to paint a flat board fully covered by adjacent non-overlapping rectangle