POJ.1185 炮兵阵地

来源:互联网 发布:电火花电脉冲编程 编辑:程序博客网 时间:2024/05/21 18:38

【题意】中文题目,题意很简单!

【解题方法】

首先我们求的是最多能放多少个炮兵,那么假如我把所有的情况都枚举了,然后在得到的结果里面找一个最大值,那么是不是就可以了。其实这个题目的思想就是这么简单。

但是我们如果用一般的枚举的方法肯定会超时,那么就用到了状态压缩。因为这个题目中一个炮影响的是两行,所以我们要多定义一维的状态来表示当前行的上上一行的状态。 状态:dp【i】【j】【k】 第 i 行,状态为 k ,第 i-1 行状态为 j 的最大放的炮兵数目

转移方程 dp [ i ] [ j ] [ k ]  = max ( dp [ i ] [ j ] [ k ] , dp [ i - 1 ] [k ] [ l ] + num [ j ] )

【AC代码和详细解释】

////Created by just_sort 2016/12/21//Copyright (c) 2016 just_sort.All Rights Reserved////#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/tree_policy.hpp>//#include <ext/pb_ds/hash_policy.hpp>#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <sstream> //isstringstream#include <iostream>#include <algorithm>using namespace std;//using namespace __gnu_pbds;typedef long long LL;//typedef pair<int, LL> pp;#define REP(i, n) for(int i = 0; i < n; i++)#define REPZ(i, n) for(int i = 1; i <= n; i++)#define MP(x,y) make_pair(x,y)const int maxn = 1100;const int maxm = 1<<12;const int inf = 0x3f3f3f3f;//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;//headint n, m, num[110], top; //记录每一行拥有的炮兵的个数int st[70], cur[110];//每一行的转态和输入的地的状态int dp[110][70][70]; //dp[i][j][k]在第i行状态为j,在第i-1行状态为k的最大方案数bool judge1(int x)//判断二进制相邻的1或者间隔2个位置,即是炮兵横着不能攻击到{    if(x&(x<<1) || x&(x<<2)) return false;    else return true;}bool judge2(int i, int k)//判断当前行和上一行的状态是否出现冲突{    return cur[i] & st[k];}void init1() //关键数组初始化{    memset(num, 0, sizeof(num));    memset(st, 0, sizeof(st));    memset(cur, 0, sizeof(cur));    memset(dp, 0, sizeof(dp));    top = 0;}void init2() //对不必要的状态进行剔除{    int total = 1 << m;    for(int i = 0; i < total; i++)    {        if(judge1(i)) st[++top] = i;    }}//int cal(int x) //计算状态x里面1的个数//{//    int cnt = 0;//    while(x)//    {//        if(x&1) cnt++;//        x >>= 1;//    }//    return cnt;//}int main(){    while(scanf("%d%d", &n, &m)!=EOF)    {        init1();        init2();        char x;        int ans = 0;        for(int i = 1; i <= n; i++) //输入的地的状态        {            getchar();            for(int j = 1; j <= m; j++)            {                scanf("%c", &x);                if(x =='H') cur[i] += (1 << (j-1));            }        }        //初始化DP装态        for(int i=1; i<=top; i++)        {            num[i] = __builtin_popcount(st[i]);            if(!judge2(1, i))            {                dp[1][i][1] = num[i];  //第1行状态为i,第0行状态为                ans = max(ans, num[i]); //更新一下当前最大值            }        }        //状态转移        for(int i = 2; i <= n; i++) //枚举行        {            for(int j = 1; j <= top; j++)//当前行状态            {                if(judge2(i, j)) continue;                for(int l = 1; l <= top; l++) //上上行状态                {                    if(st[j] & st[l]) continue;                    for(int k = 1; k <= top; k++){ //上一行状态                        if(st[j] & st[k]) continue;                        dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + num[j]); //状态转移                        ans = max(ans, dp[i][j][k]); //更新答案                    }                }            }        }        //输出答案        printf("%d\n", ans);    }    return 0;}

0 0
原创粉丝点击