您的位置:首页 > 其它

HOJ2662

2018-01-29 22:16 176 查看
题意:给出N,M列棋盘,N*M<=80,放K个棋子,其中棋子不能相邻,问有多少种放法?

题解:考虑dp[i][j][t] 为到第i行放了j个棋子,且当前状态为t的方法数,则转移为dp[i][j][t] = sum(dp[i-1][j-num(mark[t])][tt])

#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;

using namespace std;

#define SZ(X) ((int)X.size())

#define mp make_pair

#define pb push_back

#define RALL(X) X.rbegin(),X.rend()

#define ALL(X) X.begin(),X.end()

#define mem(a,c) memset(a,c,sizeof(a));

using ll = long long ;

using ld = long double ;

ll dp[82][22][1<<9];

int sz;

int mark[1<<9];

bool ck(int x)

{

    return !(x & (x << 1));

}

int num(int x)

{

    return __builtin_popcount(x);

}

int main()

{

    int n, m, k;

    while(scanf("%d%d%d",&n,&m,&k) != EOF) {

        mem(dp, 0);

        mem(mark, 0);

        if(n < m) swap(n, m);

        sz = 0;

        for(int i = 0;i < 1 << m;i ++) {

            if(ck(i)) {

                ++ sz;

                mark[sz] = i;

                dp[1][num(i)][sz] = 1;

            }

        }

        for(int i = 2;i <= n;i ++) {

            for(int _k = 0;_k <= k;_k ++) {

                for(int now = 1;now <= sz;now ++) {

                   
4000
for(int last = 1;last <= sz;last ++) {

                        if(!(mark[last] & mark[now]) && _k >= num(mark[now]) ) {

                            dp[i][_k][now] += dp[i-1][_k-num(mark[now])][last];

                        }

                    }

                }

            }

        }

        ll res = 0;

        for(int i = 1;i <= sz;i ++) {

            res += dp
[k][i];

        }

        printf("%lld\n",res);

    }

    return 0;

}

/*

8 9 20

1539190688200

8 8 20

15470473563

8 7 20

56230556

9 8 20

1539190688200

9 8 10

42040864507

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: