zoukankan      html  css  js  c++  java
  • 1592:【例 1】国王

    1592:【例 1】国王


    时间限制: 500 ms         内存限制: 65536 KB
    提交数: 1169     通过数: 537

    【题目描述】

    原题来自:SGU 223

    在 n×nn×n 的棋盘上放 kk 个国王,国王可攻击相邻的 88 个格子,求使它们无法互相攻击的方案总数。

    【输入】

    只有一行,包含两个整数 nn 和 kk。

    【输出】

    每组数据一行为方案总数,若不能够放置则输出 00。

    【输入样例】

    3 2

    【输出样例】

    16

    【提示】

    样例输入 2

    4 4

    样例输出 2

    79

    数据范围与提示:

    对于全部数据,1n10,0kn21≤n≤10,0≤k≤n2 。

    思路:

    首先考虑搜索,发现可剪枝状态少;接着二维dp,发现状态难以表达

    发现国王只影响周围八个格子,也就是说国王只影响这一行的状态和上下两行的状态,可以压缩整行信息,进行状压

    f[i][j][s]表示第i行状态为a[j],前i行已经放了s个国王的方案数

    考虑如何表示a[](二进制,0表示不放,1表示放)

    算法流程:

    1.对于每一行,搜索得出一个合法状态

    2.枚举上一行与这一行相容的状态累加

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    long long f[11][155][155]={0},ans;
    int num[155],s[155],n,k,s0;
    
    void prepare()
    {
        int cnt;
        s0=0,ans=0;
    //    memset(f,0,sizeof(f));
        for(int i=0;i<(1<<n);i++)//枚举每一行的状态,总方案数为2^n
        {
            if(i&(i<<1))//检查当前状态是否冲突(当前状态是否存在两个相邻的国王)
            continue;
            cnt=0;
            for(int j=0;j<n;j++)
            if(i&(1<<j))cnt++;//k表示当前状态用掉的国王数 
            s[++s0]=i;//最终s数组中存放的是当前行的所有可用状态 
            num[s0]=cnt;
         } 
    }
    
    void dp()
    {
        f[0][1][0]=1;
        for(int i=1;i<=n;i++)//
            for(int j=1;j<=s0;j++)//状态 
                for(int kk=0;kk<=k;kk++)//国王数量
                {
                    if(kk>=num[j])//若是当前拥有的国王数比这一行需要的国王数多
                    for(int t=1;t<=s0;t++)//枚举第i-1行的状态
                    {
                        if(!(s[t]&s[j])&&!(s[t]&(s[j]<<1))&&!(s[t]&(s[j]>>1)))//没有冲突
                        f[i][j][kk]+=f[i-1][t][kk-num[j]]; 
                     } 
                 } 
        
        for(int i=1;i<=s0;i++) ans+=f[n][i][k];
        cout<<ans<<'
    ';
        /*for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=s0;j++)
            {
                for(int kk=0;kk<=k;kk++)
                    cout<<f[i][j][kk]<<" ";
                    cout<<'
    ';
            }
            cout<<'
    ';
        }
        
        cout<<s0<<"@@@@@
    ";
        cout<<f[3][3][4]<<'
    ';
        */    
                
        /*f[0][1][0]=1;//显然第0行第一位上可以放一个国王
        for(int i=1;i<=n;i++)
        for(int j=1;j<=s0;j++)
        for(int kk=0;kk<=k;kk++)
        {
            if(kk>=num[j])//先看能不能减
            for(int t=1;t<=s0;t++)
            if(!(s[t]&s[j]) && !(s[t]&(s[j]<<1)) && !(s[t]&(s[j]>>1)))//看看国王和上一行的国王起不起冲突
            f[i][j][kk]+=f[i-1][t][kk-num[j]];
        }
        for(int i=1;i<=s0;i++) ans+=f[n][i][k];//最后一行的所有状态都要加上
        cout<<ans;*/
    }
    
    int main()
    {
        cin>>n>>k;
        prepare();
        dp();//使用函数更方便 
        return 0;
    }
  • 相关阅读:
    pat每日刷题计划--day70
    pat每日刷题计划--day69
    pat每日刷题计划--day68
    pat每日刷题计划--day67
    pat每日刷题计划--day66
    SpringBoot+MyBatis+MySQL读写分离
    SpringMVC源码分析
    ActiveMQ从入门到精通(三)
    ActiveMQ从入门到精通(二)
    ActiveMQ从入门到精通(一)
  • 原文地址:https://www.cnblogs.com/yxr001002/p/14426363.html
Copyright © 2011-2022 走看看