2016.6.3

最近期末复习...没时间总结博客了 = =!


1.深搜 生日蛋糕 

题目链接:http://cxsjsx.openjudge.cn/hw201615/B/

这是一道很经典的深搜加剪枝的题目

首先澄清题意,最大表面积应该是每个蛋糕的侧面积加上最底层蛋糕的底面积。

接下来就是怎样剪枝的问题,代码里写的很详细,直接贴了

#include<iostream>  
#include<string>  
#include<cstdio>  
#include<cstring>  
#include<queue>  
#include<map>  
#include<cmath>  
#include<stack>  
#include<set>  
#include<vector>  
#include<algorithm>  
#define LL long long  
using namespace std;
int MinArea = 1 << 30;  //  存最优表面积;  
int MinV[30];       //  存第一层到该层最小体积;  
int MinA[30];       //  存第一层到该层最小面积;  
int N, M;            //  体积,层数;  
int area = 0;         //  存正在搭建的表面积;  
int MaxV(int n, int r, int h)     //  当有n层时,可以有的最大体积;其中r为最大半径,h为最大高度;  
{
    int v = 0;
    for (int i = 0; i < n; i++)
        v += (r - i)*(r - i)*(h - i);
    return v;
}
void dfs(int v, int n, int r, int h)
{
    if (n == 0)//  说明一种情况搭建层数已经完成;  
    {           
        if (v) 
            return;
        else{
            MinArea = min(MinArea, area);      //  可以搭建,则更新最优解;  
            return;
        }
    }
    if (v <= 0)//剪枝1:体积不够,退出; 
        return;                    
    if (MinV[n] > v)//剪枝2:搭建n层的最小体积比提供的体积大,即无法搭建;退出;  
        return;               
    if (area + MinA[n] >= MinArea)//剪枝3:当前搭建表面积加上前n层最小的表面积比最优解更大,则可以退出;   
        return;   
    if (h < n || r < n)//剪枝4:最大半径,或者最大高度比层数还要少,则就说明已经无法继续搭建了; 
        return;                 
    if (MaxV(n, r, h) < v) //剪枝5:这n层可以搭建的最大体积都比提供的体积要小,说明无法按要求搭建;  
        return;           
    for (int rr = r; rr >= n; rr--)
    {       //  从最大半径开始枚举搜索;  
        if (n == M) 
            area = rr*rr;        //  底面积;  
        for (int hh = h; hh >= n; hh--)
        {   //  从最大高度开始枚举;  
            area += 2 * rr * hh;       //  搭建的面积更新;  
            dfs(v - rr * rr * hh, n - 1, rr - 1, hh - 1);
            area -= 2 * rr * hh;          //  回溯;  
        }
    }
}
int main()
{
    while (~scanf("%d%d", &N, &M))
    {
        MinV[0] = 0;
        MinA[0] = 0;
        for (int i = 1; i <= M; i++)
        {
            MinV[i] = MinV[i - 1] + i*i*i;                    //  前i层最小体积;  
            MinA[i] = MinA[i - 1] + 2 * i*i;                    //  前i层最小面积;  
        }
        if (MinV[M] > N)
            printf("0\n");
        else
        {
            int MaxH = (N - MinV[M - 1]) / (M*M) + 1;             //  底层最大高度;  
            int MaxR = sqrt(double(N - MinV[M - 1]) / M) + 1;     //  底层最大半径;  
            int area = 0;
            MinArea = 1 << 30;
            dfs(N, M, MaxH, MaxR);
            if (MinArea == 1 << 30) 
                printf("0\n");
            else  printf("%d\n", MinArea);
        }
    }
    return 0;
}


2.棋盘问题

题目链接:http://cxsjsx.openjudge.cn/hw201615/A/

八皇后问题的变式。深搜的经典题目,需要熟练掌握回溯等方法。

#include <iostream>
#include <memory.h>
using namespace std;

bool row[8] = { false }; bool board[8][8];
int n;

int Find(int left, int col)
{ // 无法继续放子的情况: 剩余的棋子数比接下来的行数要多
    if (left > n - col) //注意不能是等于
        return 0;
    // 放完最后一个棋子,摆放成功一种方案
    if (left == 0)
        return 1;
    // 1. 当前行不放棋子,棋子数不变,列加1
    int result = Find(left, col + 1);
    // 2. 当前行放棋子
    for (int i = 0; i < n; i++)
        if (!row[i] && board[i][col]) // 计算在第i列放棋子的方案数
        {
            row[i] = true;
            result += Find(left - 1, col + 1);
            row[i] = false; //回溯
        }
    return result;
}
int main()
{
    int k; char line[9];
    while (cin >> n >> k)
    {
        if (n == -1 && k == -1)
            break;
        for (int i = 0; i < n; i++)
        {
            cin >> line; //字符串输入一行
            for (int j = 0; j < n; j++)
                board[i][j] = (line[j] == '#'); //棋盘区域“#”置1,可以放棋子
        }
        cout << Find(k, 0) << endl;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值