poj1185 状态dp

来源:互联网 发布:mysql存储过程怎么用 编辑:程序博客网 时间:2024/06/06 12:49

状态dp经典题目。

题目问最多能放多少炮塔,那么,根据炮塔的特性,当前行能放的炮塔状态只跟上一行和上上一行有关,再往上的行无论怎么变化都不会影响当前行的情况。

于是,可以用一个二进制数来表示当前行的状态,每行十个位置便对应2^0到2^9,正好可以用一个int范围内整数表示状态。判断当前状态和之前一行有没有在同一列的,可以直接取与,两者相与如果结果非零,则肯定有在同一列的。

每行的状态可以通过预处理获得,同时可以获得此状态下放了多少炮塔。

具体请看代码,细细体会。

代码:

#include <iostream>#include <cstring>#include <cstdio>using namespace std;int n,m;int map[110];int status[100];int sum[100];int cnt;int dp[110][100][100];bool ok(int i){    if ((i&(i<<1)))        return false;    if ((i&(i<<2)))        return false;    return true;}int getnum(int num){    int s=0;    while (num>0)    {        if (num&1)            s++;        num>>=1;    }    return s;}void find(){    memset(status,0,sizeof(status));    memset(sum,0,sizeof(sum));    cnt=0;    for (int i=0;i<(1<<10);i++)    {        if (ok(i))        {            cnt++;            status[cnt]=i;            sum[cnt]=getnum(i);        }    }}int max(int a,int b){    return a>b?a:b;}int main(){    find();    while (cin>>n>>m)    {        memset(map,0,sizeof(map));        memset(dp,-1,sizeof(dp));        for (int i=1;i<=n;i++)        {            for (int t=0;t<m;t++)            {                char p;                cin>>p;                if (p=='H')                    map[i]=map[i]|(1<<t);            }        }        int mm=0;        for (int i=1;i<=cnt;i++)        {            if (status[i]<(1<<m))                mm=i;            else                break;        }        int ans=0;        for (int i=1;i<=mm;i++)        {            if ((status[i]&map[1])==0)            {                dp[1][i][1]=sum[i];                //cout<<status[i]<<" "<<dp[1][i][1]<<endl;                ans=max(ans,dp[1][i][1]);            }        }        //cout<<status[mm]<<endl;        for (int i=2;i<=n;i++)        {            for (int t=1;t<=mm;t++)            {                if (map[i]&status[t])                    continue;                for (int k=1;k<=mm;k++)                {                    if (map[i-1]&status[k])                        continue;                    if (status[t]&status[k])                        continue;                    for (int j=1;j<=mm;j++)                    {                        if (map[i-2]&status[j])                            continue;                        if (i>2&&(status[j]&status[k]))                            continue;                        if (status[t]&status[j])                            continue;                        if (dp[i-1][k][j]==-1)                            continue;                        //cout<<i<<" "<<status[t]<<" "<<status[k]<<" "<<status[j]<<endl;                        dp[i][t][k]=max(dp[i][t][k],dp[i-1][k][j]+sum[t]);                        ans=max(ans,dp[i][t][k]);                    }                }            }        }        cout<<ans<<endl;    }}


 

0 0
原创粉丝点击