您的位置:首页 > 其它

SGU 132 状态压缩

2013-05-22 12:42 169 查看
这道题重点在于不能有连续两个相邻的空格,不光是横向的连续两个空格的空格,还有纵向的连续两个空格也不行(把握这个这题就OK了)。之前做了一些铺瓷砖的压缩DP题,都没有在纵向有神马限制。这也是这道题的难点所在。

刚开始想的状态转移方程错了(想了好半天才发现是错的。。。T..T),原因是不能解决我说的内个重点问题,于是把内个加入到DP的状态当中。

DP
[S][Q]表示第N行状态为S,Q表示第n行和第n-1行均为空的格子的状态,这些Q状态所表示的格子要在下一行放砖时填补。

还是老套路,先对每一行搜索,搜索怎么放瓷砖,这样得到两个状态s(本行新的状态),p(上一行的状态),于是,dp
[s][q]=min{dp[n-1][p'][q']+k},其中p'与p不能有重合,q'必须满足q'&p=q',再根据这些状态算出q。

最后结果是min{dp[n-1][s][0]},s要满足保证没有相邻空格,

要用滚动数组,要在每次大循环后对一组状态清零。

附代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#define M 130
#define N 72
#define u (1<<m) 
#define cl(a) memset(a,-1,sizeof(a))
#define INF 500

using namespace std;

int dp[3][M][M],a
,b[10],m,n,res;

int check(int t)
{
    int i;
    for (i=1;i<m;i++)
        if (!(t&b[i-1])&&!(t&b[i])) return 0;
    return 1;   
}

void trans(int l,int s,int p1,int p,int k)
{
    int i,q,t;
    t=p1+a[l-1]+p;
    int e=l%2;
    for (i=0;i<=p;i++)
        if ((i&p)==i)
        {
            q=u-1-(t|(s+a[l]));
            if (dp[1-e][p1][i]<0) continue;
            if (dp[e][s][q]<0) dp[e][s][q]=dp[1-e][p1][i]+k;
            else dp[e][s][q]=min(dp[e][s][q],dp[1-e][p1][i]+k);
            if (l==n&&check(s+a[l])&&!q) res=min(res,dp[e][s][q]);
        }
}

void Rundp(int l,int i,int k,int s,int p)
{
    int p1;
    if (i>=m)
    {
        for (p1=0;p1<u;p1++)
            if (!(p1&p)&&!(p1&a[l-1]))
            {
                if (check(p1+p+a[l-1])) trans(l,s,p1,p,k);
            }
        return;
    }
    if (a[l]&b[i]) Rundp(l,i+1,k,s,p);
    else
    {
        Rundp(l,i+1,k,s,p);
        if (!(a[l-1]&b[i])) Rundp(l,i+1,k+1,s+b[i],p+b[i]);
        if (i<m-1&&!(a[l]&b[i+1])) Rundp(l,i+2,k+1,s+b[i]*3,p);
    }
}

void clear(int l)
{        
    int i,j;
    for (i=0;i<u;i++)
        for (j=0;j<u;j++) dp[1-l%2][i][j]=-1;
}

int main()
{
    int i,j;
    string ss;
    cin>>n>>m;
    cl(dp);
    for (i=0;i<m;i++) b[i]=(1<<i);
    for (i=1;i<=n;i++)
    {
        cin>>ss;
        for (j=0;j<m;j++)
        {
            if (ss[j]=='*') a[i]+=(1<<j);
        }
    }
    res=INF;
    a[0]=u-1;
    dp[0][0][0]=0;
    for (i=1;i<=n;i++)
    {
        Rundp(i,0,0,0,0);
        clear(i);
    }
    cout<<res<<endl; 
    //system("pause");
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: