poj1185 炮兵阵地

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

题意:汉语

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int map[110];
int N, M;
int dp[2][65][65];//滚动数组
int state[65];
int soilder[65];
/*
状态转移方程:
dp[i][j][k] = max{ dp[i][j][k], d[i-1][k][p] + soilder[j] };
dp[i][j][k]的含义:前i行在第i行对应的第j种状态,第i-1行对应的第k种状态的情况下,总的炮兵数目。
总的状态数:M=10时,总的状态数为60.(运行get_all_state()函数即可知道)。
总的状态数的求法:在只考虑一行中互不攻击的情况下(不考虑山地的情况),一行中可以放置的炮兵的状态数。
一种状态,对应着这种状态下炮兵的数目,也对应着这种状态下一行中炮兵的分布情况。
举个例子:假设M=4.(平原为0,山地为1).一行中的输入是PPHP,即0010.
先求总的状态数:在不考虑山地的情况下,初始情况为0000.你可以在任意位置放置1,但是需要满足互不攻击的条件。
因为4位2进制数可表示32个整数,枚举这32个整数,看哪个整数满足互不攻击条件。若满足,即将这个整数记下来,并且求出这个
整数的所有的1.(即放置炮兵的数目)。
以上就是状态压缩:把一行输入看成一组2进制数,并转换成10进制存储。
其实这题最难想的还是状态转移方程。
*/
//只考虑互不攻击,未考虑山地的情况
//当M=10,所有的状态数为60
int get_all_state() {
    int i, num;
    for(i=0, num=0; i<(1<<M); i++) {
        int k = i;
        if(((k<<1)&i) || ((k<<2)&i)) continue;
        state[num] = i;
        while(k) {
            soilder[num]++;
            k=k&(k-1);
        }
        num++;
    }
    return num;
}
int main()
{
    freopen("/home/lsy/Desktop/2.txt", "r", stdin);
    cin >> N >> M;
    int i, j, k, p;
    char ch;
    for(i=0; i<N; i++) {
        map[i] = 0;
        for(j=0; j<M; j++) {
            cin >> ch;
            if(ch == 'H') k=1;
            else k=0;
            map[i] = map[i]*2+k;
        }
    }
    int kind = get_all_state();
    //cout << "kind=" << kind << endl;
    memset(dp, -1, sizeof(dp));
    for(i=0; i<kind; i++) {
        if((state[i]&map[0]) == 0) dp[0][i][0] = soilder[i];
    }
    for(i=1; i<N; i++) {
        for(j=0; j<kind; j++) {
            for(k=0; k<kind; k++) {
                for(p=0; p<kind; p++) {
                    if(state[j]&map[i]) continue;
                    if(state[j]&state[k] || state[j]&state[p] || state[k]&state[p]) continue;
                    if(dp[(i-1)%2][k][p] != -1)
                        dp[i%2][j][k] = max(dp[i%2][j][k], dp[(i-1)%2][k][p] + soilder[j]);
                }
            }
        }
    }
    int ans = 0;
    for(k=0; k<kind; k++)
        for(j=0; j<kind; j++) {
            if(ans < dp[(i-1)%2][k][j]) ans = dp[(i-1)%2][k][j];
        }
    cout << ans << endl;
    return 0;
}
总结:状态的表示和状态转移方程比较难想。看来做动态规划的题目,先得表示所有状态,再写出状态转移方程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值