zoukankan      html  css  js  c++  java
  • hoj2662 Pieces Assignment

    Pieces Assignment

    My Tags   (Edit)
      Source : zhouguyue
      Time limit : 1 sec   Memory limit : 64 M

    Submitted : 684, Accepted : 235

    Background

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

    Input

        本题有多组测试数据,每组输入包含三个正整数n,m和k。

    Output

        对于每组输入,输出只有一个正整数,即合法的方案数。

    Sample Input

    2 2 3
    4 4 1

    Sample Output

    0
    16
    /*
        对于每一行,如果把没有棋子的地方记为0,有棋子的地方记为1,那么每一行的状态都可以表示成一个2进制数,进而将其转化成10进制。
        那么这个问题的状态转移方程就变成了
        设dp[ i ] [ j ][k ]表示当前到达第i列,一共使用了j个棋子,且当前行的状态在压缩之后的十进制数为k 时的状态总数。那么我们也可以类似的写出状态转移方程:
         dp[ i ][ j ][ k ]=sum( dp[ i-1][ j-num(k) ][ w ] )   num(k)表示 k状态中棋子的个数,w表示前一行的状态。
        虽然写出了状态转移方程,但是还是有很多细节问题需要解决:比如,如何保证当前状态是合法的?
        最基本的做法是:首先判断k状态是否合法,也就是判断在这一行中是否有2个旗子相邻,然后枚举上一行的状态w,判断w状态是否合法,然后判断k状态和w状态上下之间是否有相邻的棋子。
        当然这样做的时间复杂度是很高的,也就是说有很多地方可以优化.
        比如:判断每一行状态是否合法,可以在程序一开始判断然后保存结果,判断k状态和w状态上下之间是否有相邻的棋子,可以利用位运算,if(k&w)说明上下之间有相邻的棋子等等。
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,k,sum[1<<9],cnt,mark[1<<9];
    long long dp[81][21][1<<9],ans;//dp[i][j][k]到第i行,共用了j个棋子,状态为k 
    int count(int x){
        int res=0;
        while(x){
            if(x&1)res++;
            x>>=1;
        }
        return res;
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        while(scanf("%d%d%d",&n,&m,&k)!=EOF){
            ans=0;cnt=0;
            memset(dp,0,sizeof(dp));
            if(m>n)swap(m,n);
            for(int i=0;i<(1<<m);i++)
                if(!(i&(i<<1))){
                    sum[++cnt]=count(i);
                    mark[cnt]=i;
                    dp[1][sum[cnt]][cnt]=1;
                }
            for(int i=2;i<=n;i++)
                for(int j=0;j<=k;j++)
                    for(int t=1;t<=cnt;t++)
                        for(int p=1;p<=cnt;p++)
                            if(!(mark[t]&mark[p])&&j>=sum[t]){
                                dp[i][j][t]+=dp[i-1][j-sum[t]][p];
                            }
            for(int i=1;i<=cnt;i++){
                ans+=dp[n][k][i];
            }
            printf("%lld
    ",ans);
        }
    }
    100分 状压dp
  • 相关阅读:
    (第七周)评论alpha发布
    (第六周)工作总结
    (第六周)团队项目6
    (第六周)团队项目5
    (第六周)团队项目4
    (第六周)团队项目燃尽图
    (第六周)团队项目3
    (第六周)课上Scrum站立会议演示
    Java第二次作业第五题
    Java第二次作业第四题
  • 原文地址:https://www.cnblogs.com/thmyl/p/7337590.html
Copyright © 2011-2022 走看看