zoukankan      html  css  js  c++  java
  • 18.5.25 深搜作业

    A:棋盘问题

    描述

    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。输入输入含有多组测试数据。
    每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
    当为-1 -1时表示输入结束。
    随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
    输出对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

    样例输入

    2 1
    #.
    .#
    4 4
    ...#
    ..#.
    .#..
    #...
    -1 -1
    

    样例输出

    2
    1
    

    来源

    蔡错@pku

     1 #include <iostream>
     2 #include <string>
     3 #include <cstdio>
     4 #include <memory.h>
     5 #include <map>
     6 #include <math.h>
     7 using namespace std;
     8 const int maxn =15;
     9 int hangput[maxn], lieput[maxn],chess[maxn][maxn];
    10 char thisline[maxn];
    11 int n, k, sum=0;
    12 
    13 void solve(int hang,int num) {
    14     if (num == 0)
    15     {
    16         sum++;
    17         return;
    18     }
    19         for(int j=1;j<=n;j++)
    20             if (chess[hang][j] && !lieput[j])
    21             {
    22                 //place the chess
    23                 if (num - 1 == 0)
    24                     sum++;
    25                 else
    26                 {
    27                     lieput[j] = 1;
    28                     for (int i = hang + 1; i <= n - num + 2; i++)
    29                         solve(i, num - 1);
    30                     lieput[j] = 0;
    31                 }
    32             }
    33 }
    34 
    35 void init() {
    36     while (scanf("%d%d", &n, &k) && (n != -1 || k != -1)) {
    37         sum = 0;
    38         for (int i = 1; i <= n; i++)
    39             for(int j=1;j<=n;j++)
    40         {
    41                 char ch;
    42                 cin >> ch;
    43                 if (ch == '#')
    44                     chess[i][j] = 1;
    45                 else chess[i][j] = 0;
    46         }
    47         for (int i = 1; i <= n - k + 1; i++)
    48             solve(i, k);
    49         printf("%d
    ", sum);
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     init();
    56     return 0;
    57 }
    View Code

    比较水,和后面一道形成了鲜明的对比

    B:生日蛋糕

    描述

    7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
    设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
    由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
    令Q = Sπ
    请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
    (除Q外,以上所有数据皆为正整数)
    输入有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。输出仅一行,是一个正整数S(若无解则S = 0)。

    样例输入

    100
    2

    样例输出

    68

    提示

    圆柱公式
    体积V = πR2H
    侧面积A' = 2πRH
    底面积A = πR2
    来源

    Noi 99

     1 #include <iostream>
     2 #include <string>
     3 #include <cstdio>
     4 #include <memory.h>
     5 #include <algorithm>
     6 #include <math.h>
     7 using namespace std;
     8 const int maxn =15;
     9 int n,m,smin=999999;
    10 const int maxnum = 9999999;
    11 
    12 void solve(int v,int k,int topr,int toph,int S) {
    13     if (k == 0)
    14     {
    15         if (v == 0)
    16             smin=min(S,smin);
    17         return;
    18     }
    19     if (S + 2 * (v / topr) > smin)
    20         return;
    21     if ((unsigned)(topr - 1)*(unsigned)(topr - 1)*(unsigned)(toph - 1)*k < v)
    22         return;
    23     int topv = v - k * (k - 1) / 2,_min=maxnum;
    24     for(int i=topr-1;i>=k;i--)
    25         for (int j = k; j < toph; j++)
    26         {
    27             int _v = i * i*j;
    28             if (_v*k < v)
    29                 continue;
    30             if (_v<v / k)
    31                 continue;
    32             if (_v > topv)
    33                 continue;
    34             int s = 2 * i*j;
    35             if (s + k*(k-1)/2 > smin)
    36                 continue; 
    37             int sums = s + S;
    38             if (k == m)
    39                 sums+=i*i;
    40             solve(v - _v, k - 1, i, j, sums);
    41         }
    42 }
    43 
    44 void init() {
    45     scanf("%d%d", &n, &m);
    46     int maxr = sqrt(n);
    47     solve(n, m, maxr, n,0);
    48     printf("%d
    ", smin);
    49 }
    50 
    51 int main()
    52 {
    53     init();
    54     return 0;
    55 }
    View Code

    一开始我把深搜函数设置为返回S值,如果不能就返回一个超大值……果断TLE。后来想是不是这样每次调用min太慢了,改成了void,直接在函数中在边界条件做判断取最小值,快了巨多……

    一开始我的剪枝全部在循环内部,我也在想这样剪枝是不是有点弱……果然太弱……

    其实……剪枝只要一个就可以了……就是那个 if (S + 2 * (v / topr) > smin) (最优化剪枝)

    最难想,但剪掉的最多

    其他……感觉不是特别有用……

    然后 (unsigned)(topr - 1)*(unsigned)(topr - 1)*(unsigned)(toph - 1)*k < v 不加 unsigned 会WA,因为会出现溢出。感谢洛谷提供的数据TUT

    但是那个条件好像没什么用……

    注定失败的战争,也要拼尽全力去打赢它; 就算输,也要输得足够漂亮。
  • 相关阅读:
    mongodb 的安装历程
    从C的声明符到Objective-C的Blocks语法
    #译# Core Data概述 (转)
    避免在block中循环引用(Retain Cycle in Block)
    GCD和信号量
    Blocks的申明调用与Queue当做锁的用法
    [译]在IB中实现自动布局
    清理Xcode的技巧和方法
    SVN的Status字段含义
    iOS应用崩溃日志揭秘2
  • 原文地址:https://www.cnblogs.com/yalphait/p/9087920.html
Copyright © 2011-2022 走看看