• POJ 1185 解题报告 炮兵阵地




    题目是中文的,我就不描述题意了。
    题目用到的主要算法是状态压缩dp。

    思路是,我们要知道n行最多的炮数,只要知道n-2行所有状态最多的炮数,就可以根据n-1行和n行最多可行的状态算出。也就是说,n-2行以前的炮无论怎样放,都不会影响到第n行炮的放法。
      1
      2#include <cstdio>
      3#include <cmath>
      4#include <cstdlib>
      5
      6const int large = (int)pow( 210 );
      7int n,m;
      8char map[105][15];
      9int dp[60][60][101];
     10int stack[large];
     11int len = 0;
     12
     13//now是当前行,last是上一行,n是行号。其中,now,last都是stack的下标,不是状态
     14int Fun( int now, int last, int n )
     15{
     16    int max = 0;
     17    int s = 0;
     18    int tmp = stack[now]|stack[last]; //已放了炮的列
     19    if ( dp[now][last][n] != -1 ) return dp[now][last][n];
     20    //统计now状态放了多少炮
     21    for ( int i = 0; i < m; ++i )
     22    {
     23        if ( (stack[now]&(~(1<<i))) != stack[now] ) ++s;
     24    }

     25    if ( n == 1 ) //结束条件,第一行则返回此行的炮数
     26    {
     27         dp[now][last][1= s;
     28         return s;
     29    }

     30    for ( int i = 0; i < len; ++i )
     31    {
     32        int flag = 1;
     33        int s = 0;
     34        if ( tmp&stack[i] ) continue//若相互冲突则不算
     35        //若此状态的炮兵放在了山地也不算
     36        for ( int j = 0; j < m; ++j ) 
     37        {
     38            if ( map[n-2][j] == 'H' && (stack[i]&(~(1<<j))) != stack[i] )
     39            {
     40                     flag = 0;
     41                     break;
     42            }

     43        }

     44        if ( flag ) max >?= Fun( last, i, n-1 ); //从所有状态里挑最大的保存
     45    }

     46    max += s; //再加上now这行的炮数
     47    dp[now][last][n] = max;
     48    return max;
     49}

     50
     51//此函数用来判断是不是超出范围
     52bool OK( int a )
     53{
     54     if ( a<0 || a>= m ) return false;
     55     else return true;
     56}

     57
     58int main()
     59{
     60    int power;
     61    int max = 0;
     62    scanf( "%d%d"&n, &m );
     63    power = (int)pow( 2, m );
     64    
     65    //第0行初始化为山地
     66    for ( int i = 0; i < m; ++i ) map[0][i] = 'H';
     67    
     68    //读入数据储存到map中
     69    for ( int i = 1; i <= n; ++i )
     70    {
     71        scanf( "%s", map[i] );
     72    }

     73
     74    /*在0~power这么多状态中,绝大部分状态是可以舍弃的,因为相邻和隔一个的位置不能同时放炮。我们先把不能出现的状态剔除,将可能出现的状态储存在stack数组里,可以节约时间和空间。*/
     75    //初始化stack,test OK 
     76    for ( int i = 0; i < power; ++i )
     77    {
     78        int flag = 0;
     79        for ( int j = 0; j < m; ++j )
     80        {
     81            if ( (i&(~(1<<j))) != i )//如果i的j位是1,也就是放炮兵部队 
     82            {
     83                 if ( OK(j-1&& (i&(~(1<<(j-1))))!=i ) //j-1位合法且放了炮兵,则不合要求 
     84                 {
     85                      flag = 1
     86                      break;
     87                 }

     88                 if ( OK(j-2&& (i&(~(1<<(j-2))))!=i ) //j-1位合法且放了炮兵,则不合要求 
     89                 {
     90                      flag = 1
     91                      break;
     92                 }

     93                 if ( OK(j+1&& (i&(~(1<<(j+1))))!=i ) //j-1位合法且放了炮兵,则不合要求 
     94                 {
     95                      flag = 1
     96                      break;
     97                 }

     98                 if ( OK(j+2&& (i&(~(1<<(j+2))))!=i ) //j-1位合法且放了炮兵,则不合要求 
     99                 {
    100                      flag = 1
    101                      break;
    102                 }

    103            }
     
    104        }

    105        if ( flag == 0 )
    106        {
    107             stack[len++= i;
    108        }

    109    }

    110    
    111    //初始化dp数组
    112    for ( int i = 0; i < 60++i )
    113    {
    114        for ( int j = 0; j < 60++j )
    115        {
    116            for ( int k = 0; k < 101++k )
    117            {
    118                dp[i][j][k] = -1;
    119            }

    120        }

    121    }

    122
    123    //取遍所有本行和相邻的上一行的所有状态,取最大保留。并在传参前确保传入的参数是合法的。
    124    for ( int i = 0; i < len; ++i )
    125    {
    126        for ( int j = 0; j < len; ++j )
    127        {
    128            int flag = 1;
    129            if ( (stack[i]&stack[j]) ) continue//如果同一列同时有炮则舍弃
    130            for ( int k = 0; k < m; ++k )//剔除不合法的情况 
    131            {
    132                if ( map[n][k] == 'H' && (stack[i]&(~(1<<k)))!=stack[i] ) //此状态在山地方了炮
    133                {
    134                     flag = 0;
    135                     break;
    136                }

    137                if ( map[n-1][k] == 'H' && (stack[j]&(~(1<<k)))!=stack[j] )
    138                {
    139                     flag = 0;
    140                     break;
    141                }

    142            }

    143            if ( flag ) max >?= Fun( i, j, n ); //取最大存在max里
    144        }

    145    }

    146    printf( "%d\n", max );
    147   
    148    return 0;
    149}

    150



  • 相关阅读:
    MVC上传文件并模拟进度条
    C#文件的压缩和解压(ZIP)使用DotNetZip封装类操作zip文件(创建/读取/更新)实例
    Inherits、CodeFile、CodeBehind的区别
    .csproj文件的配置 IIS可以调试
    C# <%@ Register %>指令
    将n行3列的数据dataTable装换成m行7列的dataTable
    在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: 命名管道提供程序, error: 40
    Js全选,插入实现
    Jquery autocomplete插件的使用
    jquery.autocomplete自动补全功能
  • 原文地址:https://www.cnblogs.com/PureMilk/p/1245948.html
Copyright © 2020-2023  润新知