状态压缩DP POJ 1185 炮兵阵地

来源:互联网 发布:域名冲突怎么解决 编辑:程序博客网 时间:2024/04/28 23:58

【题目链接】http://poj.org/problem?id=1185

【题目大意】在平原(P)上可以布置一支炮兵部队,而在山地(H)上不能够部署炮兵部队。而且每两个炮兵之间的间隔(横纵)要大于等于 2,求最多能够摆放多少的炮兵部队。

【解题思路】经典状态压缩DP。每行炮兵的状态 i,只与i-1,和i-2行状态有关。若用0表示此处不能放,1表示能放。则根据题意可知:1、有些地方不能放置;2、每种状态中任意两个1之间的间隔要大于等于2(保证横着不互相攻击)。因为是和前两行的状态有关,所以要开个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数) 

【状态表示】dp[i][j][k] 表示第i行的状态为第k个状态,第i-1状态为第j 个状态时的最大炮兵个数。 

【状态转移方程】 dp[i][j][k] = max(dp[i][j][k], dp[i-1][z][j] + num[k]);num[k]为第k个状态中1的个数 

【DP边界条件】dp[1][1][i] =num[i] 状态i能够满足第一行的硬件条件(注意:这里的i指的是第i个状态,不是一个二进制数,开一个数组保存二进制状态) 

【代码实现】

#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>using namespace std;char str[110][20];int h_pos[110], p_pos[110];int n, m;int num[250];int top;int dp[110][60][60];bool ok(int x){    if(x & (x << 1)) return 0;    if(x & (x << 2)) return 0;    return 1;}void init(){    int tot = 1 << m;    top = 0;    for(int i = 0; i < tot; i ++)    {        if(ok(i)) p_pos[++top] = i;    }}//计算一个数的二进制数中1的个数,即找每种状态中能放置炮兵的个数int count1(int x){    int cnt = 0;    while(x)    {        //if(x & 1) cnt ++;       // x >>= 1;       cnt ++;       x &= (x-1);    }    return cnt;}//判断状态x是否适合第y行,即判断第y行中‘H’的位置与炮兵的位置是否冲突bool isfit(int x, int y){    if(h_pos[y] & x) return 0;    return 1;}int  main(){    //输入n行m列个字符,每行仅由P和H组成    while(~scanf("%d %d", &n, &m) && n+m)    {        for(int i = 1; i <= n; i ++)        {            scanf("%s", str[i]+1);        }        //两个炮兵之间的间距不能小于3,筛选符合条件的        init();        //计算每行中H的个数,并用二进制的形式进行存储在数组h_pos中        for(int i = 1; i <= n; i ++)        {            h_pos[i] = 0;            for(int j = 1; j <= m; j ++)            {                if(str[i][j] == 'H')                    h_pos[i] += (1 << (j-1));            }        }       // printf("%d\n", top);        memset(dp, -1, sizeof(dp));        for(int i = 1; i <= top; i ++)        {            num[i] = count1(p_pos[i]);           // printf("num[i]=%d \n", num[i]);            if(isfit(p_pos[i], 1))                dp[1][1][i] = num[i];        }        for(int i = 2; i <= n; i ++)        {            for(int k = 1; k <= top; k ++)            {                if(!isfit(p_pos[k], i)) continue;                for(int j = 1; j <= top; j ++)                {                    if(p_pos[j] & p_pos[k]) continue;                    for(int z = 1; z <= top; z ++)                    {                        if(p_pos[z] & p_pos[k]) continue;                        if(dp[i-1][z][j]== -1) continue;                        dp[i][j][k] = max(dp[i][j][k], dp[i-1][z][j] + num[k]);                    }                }            }        }        int ans = 0;        for(int i = 1; i <= n; i ++)            for(int j = 1; j <= top; j ++)                for(int k = 1; k <= top; k ++)                    ans = max(ans, dp[i][j][k]);        printf("%d\n", ans);    }    return 0;}





原创粉丝点击