zoukankan      html  css  js  c++  java
  • 【算法•日更•第十四期】信息奥赛一本通1592:【例 1】国王题解

      废话不多说,直接上题:


    1592:【例 1】国王


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

    【题目描述】

    原题来自:SGU 223

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

    【输入】

    只有一行,包含两个整数 n 和 k。

    【输出】

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

    【输入样例】

    3 2

    【输出样例】

    16

    【提示】

    样例输入 2

    4 4

    样例输出 2

    79

    数据范围与提示:

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

    【来源】


      不得不说,这道题太像还是n皇后了。详见此题链接:戳这里哦~

      只不过是皇后变成了国王、地图上没有了坑而已。

      不过我们可以先看一看数据规模,我一下子就被惊到了。n只有10,k只有100,但是虽然数据小,但是搜索要真的一个一个搜起来,那可就真的是指数级复杂度,肯定不行。 

      于是我们就不得不选择优化,这道题属于状态压缩类动态规划,在不久前小编就已经使用过了,其实说白了就是使用二进制优化。

      众所周知,二进制是这样的:1010110,一堆0和1,但是如果你的地图是由0、1组成的,那么就可以这样优化。

      图解一下:

      其实是从一本通提高篇上copy下来的。

      那么一行的数据就浓缩成一个数了,那么我们在处理1时就只要用lowbit原理x&-x就可以找到最高位的1了(别问我为什么,别的大佬都不太清楚)。

      好了,回归正题,这道题是动态规划题,那么怎样设计状态呢?

      我们要在n*n的棋盘上放k个国王,那么我们不妨用f[i][j][k]来表示第i行的状态是a[j](二进制表示),目前为止放了k个棋子。

      显然f[i][j][k]=sum{i-1,l,k-num[j]}(不发生冲突),其中l是,枚举上一行状态的变量,num[j]是a[j]这一状态可以放置的国王数。

      行了,其他的都看注释吧,要不然不好解释,代码如下:

     1 #include<iostream>
     2 using namespace std;
     3 long long n,K,num[1000],a[1000],sum,ans,f[300][300][300];
     4 void pre()
     5 {
     6     int cnt=0;//记录方案数 
     7     for(int i=0;i<(1<<n);i++)//注意,这里模拟的是一行的所有状态,而不是行数 
     8     {
     9         if(i&(i<<1)) continue;//如果结果不是0,那么就会有1是挨着的,不合法 
    10         cnt=0;
    11         for(int j=0;j<n;j++) if((1<<j)&i) cnt++;//如果i的二进制表示下的j位有1,那么就记录 
    12         a[++sum]=i;//记录状态 
    13         num[sum]=cnt;//记录可以放国王的数量 
    14     }
    15 }
    16 void dp()
    17 {
    18     f[0][1][0]=1;//显然第0行第一位上可以放一个国王 
    19     for(int i=1;i<=n;i++)
    20     for(int j=1;j<=sum;j++)
    21     for(int k=0;k<=K;k++)
    22     {
    23         if(k>=num[j])//先看能不能减 
    24         for(int l=1;l<=sum;l++)
    25         if(!(a[l]&a[j]) && !(a[l]&(a[j]<<1)) && !(a[l]&(a[j]>>1)))//看看国王和上一行的国王起不起冲突 
    26         f[i][j][k]+=f[i-1][l][k-num[j]];
    27     }
    28     for(int i=1;i<=sum;i++) ans+=f[n][i][K];//最后一行的所有状态都要加上 
    29     cout<<ans;
    30 }
    31 int main()
    32 {
    33     cin>>n>>K;
    34     pre();dp();
    35     return 0;
    36 }
  • 相关阅读:
    yii框架源码分析之Yii::createWebApplication()>run() 执行过程分析
    PHP的范围解析操作符(::)的涵义
    数据结构&算法(PHP描述) 三元组 Triplet
    解决远程连接mysql很慢的问题(mysql_connect 打开连接慢)
    第4章 数据处理数组的处理郑阿奇
    PHP相似函数整理2 array_flip() 、array_reverse()
    OS + Linux Disk disk lvm / disk partition / disk mount / disk io
    my read_Country
    OS + Linux File nfs / samba / rsync / inotify / smb / webdav
    Unix + OS IBM Aix Disk disk lvm / disk partition / disk mount / disk mon / File
  • 原文地址:https://www.cnblogs.com/TFLS-gzr/p/11202543.html
Copyright © 2011-2022 走看看