Day 05 DP_Basic 02 总结

 

今日AC题目列表:

HOJ 1192 Dollars

HOJ 1714 Minimax Triangulation

HOJ 2156 Colored stones

HOJ 2558 maxsum

HOJ 2662 Pieces Assignment

 

今天效率超级低啊,> . <,下午竟然手残把数组下标写反了。

 

HOJ 2622 Pieces Assignment 解题报告

题目大意:

      有一个n*m的棋盘(n、m≤80,n*m≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻(每个棋子最多和周围4个棋子相邻)。求合法的方案总数。

具体思路:

      注意到n*m<=80,可得到max(min(n,m)) 为8,于是最大可以用1<<8-1表示一行的棋子的状态。

      于是f[i][j][r] = Σf[i-1][k][r-t(j)] t(j)是j这种状态里面棋子的个数,如果k & j != 0表示上一行和这一行有矛盾,此种状态不成立。

      初始值f[0][0][0] = 1

      每次判断j这种状态自身是否合法即可。

 

附上代码

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

using namespace std;

long long f[81][1<<9][21];

inline int getnum(int x)
{
    int s = 0 , tmp = 0;
    while (x)
    {
        if (s && (x & 1)) return -1;
        if (s = (x & 1)) tmp++;
        x = x >> 1;
    }
    return tmp;
}

int main()
{
    int n, m, t;
    while(scanf("%d%d%d", &n, &m, &t) != EOF)
    {
        if (n < m) swap(n, m);

        memset(f,0,sizeof(f));
        f[0][0][0] = 1;
        for (int i = 1; i <= n; i++)
            for (int r = 0; r <= t; r++)
            for (int j = 0; j < (1<<m); j++)
            {
                int num = getnum(j);
                if (num == -1 || num > r) continue;
                for (int k = 0; k < (1<<m); k++)
                {
                    if (getnum(k) == -1 || (k & j) ) continue;
                    f[i][j][r] += f[i-1][k][r-num];
                }
            }
        long long ans = 0;
        for (int i = 0; i < (1<<m); i++) ans += f[n][i][t];
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2012-07-27 21:08  Ijingo  阅读(334)  评论(0编辑  收藏  举报