zoukankan      html  css  js  c++  java
  • 互不侵犯

    【题目描述】

    在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

    【输入描述】

    只有一行,包含两个数N、K(1 <= N <= 9,0 <= K <= N*N)。

    【输出描述】

    输出一行,包含一个整数,表示方案数。

    【样例输入】

    3 2

    【样例输出】

    16

    50分暴搜(暴力都不会写,我真是弱得无人能及!):

    源代码:
    
    #include<cstdio>
    int n,k,ans(0),x[8]={1,1,1,0,0,-1,-1,-1},y[8]={-1,0,1,1,-1,-1,0,1};
    bool f[10][10];
    void DFS(int X,int Y,int S) //如下图,一行接一行地搜索,避免重复,值得借鉴。
    {
        if (S==k)
        {
            ans++;
            return;
        }
        if ((n-X)*n+(n-Y)<=(k-S)) //A*优化。
          return;
        for (int a=X;a<=n;a++)
          for (int b=1;b<=n;b++)
            if (!f[a][b]&&(a>X||b>Y))
            {
                bool t(0);
                for (int c=0;c<8;c++)
                  if (f[a+x[c]][b+y[c]]) //值得借鉴,周围有国王就不成立。
                  {
                    t=true;
                    break;
                  }
                if (!t)
                {
                    f[a][b]=true;
                    DFS(a,b,S+1);
                    f[a][b]=false;
                }
            }
    }
    int main() //Re:从制杖开始的沙茶生活。
    {
        scanf("%d%d",&n,&k);
        for(int a=1;a<=n;a++)
          for(int b=1;b<=n;b++)
          {
            f[a][b]=true;
            DFS(a,b,1);
            f[a][b]=false;
          }
        printf("%d",ans);
        return 0;
    }
    
    /*
        *****
        *****
        **#..
        .....
        .....
        设当前点为"#",则搜索区域为"."。
    */

    状态压缩动态规划(正解):

    源代码:
    
    #include<cstdio>
    long long f[10][101][512],Ans; //注意数据类型。
    int M,N,K,Stay[101],Num[101]; //Stay[]记录每种状态压缩后的值,Num[]记录对应的状态中1的个数。
    bool Map[101][101];
    void DFS(int k,int Place,int Now) //k是放了几颗,Place是当前放的位置,Now是当前状态压缩后的值。
    {
        Stay[++M]=Now;
        Num[M]=k;
        if (k>=(N+1)/2||k>=K) //边界剪枝。
          return;
        for (int a=Place+2;a<=N;a++) //国王不相邻。
          DFS(k+1,a,Now+(1<<(a-1))); //注意,状态是颠倒的。
    }
    void Init()
    {
        DFS(0,-1,0); //预处理出一行的每种状态,共有M种。
        for (int a=1;a<=M;a++)
          for (int b=1;b<=M;b++)
            Map[a][b]=Map[b][a]=((Stay[a]&Stay[b])||((Stay[a]>>1)&Stay[b])||((Stay[a]<<1)&Stay[b]))?0:1; //预处理状态共存情况。
        for (int a=1;a<=M;a++)
          f[1][Num[a]][a]=1; //预处理边界。
    }
    int main() //状态压缩DP。
    {
        scanf("%d%d",&N,&K);
        Init();
        for (int a=2;a<=N;a++) //行数,1为边界,从2开始转移。
          for (int b=0;b<=K;b++) //棋子数。
            for (int Now=1;Now<=M;Now++) //这一行的情况。
            {
                if (Num[Now]>b) //大于所给棋子数,跳过。
                  continue;
                for (int k=1;k<=M;k++) //枚举上一行的状态。
                  if (Map[k][Now]&&Num[k]+Num[Now]<=b)
                    f[a][b][Now]+=f[a-1][b-Num[Now]][k]; //方案数转移。
            }
        for (int a=1;a<=M;a++) //总数统计。
          Ans+=f[N][K][a];
        printf("%lld",Ans);
        return 0;
    }
  • 相关阅读:
    阿里的面试官都喜欢问哪些问题?
    Spring AOP中的JDK和CGLib动态代理哪个效率更高?
    招聘季!送你21套经典面试题!助你一臂之力!
    Spring AOP中的JDK和CGLib动态代理哪个效率更高?
    为什么需要分布式配置中心?
    线上出故障了!我慌得一匹!教大家如何应对在线故障!
    阿里巴巴的26款超神Java开源项目!
    完了!生产事故!几百万消息在消息队列里积压了几个小时!
    十大经典排序算法(动图演示)
    用户画像学习笔记
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5773908.html
Copyright © 2011-2022 走看看