hdu 4539 郑厂长系列故事——排兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=4539

状态压缩+dp

此题给人感觉状态数比较多 但是由于自身有一定的限制所以说 根本不到(1<<10) 自己测一下的话还不到 200

如果再加上输入矩阵的限制 每一行的状态数就更少了 大胆的用for循环就是了

可怜的是我在比赛中大脑短路没想到

用了一种很恶心的方法 就是把图斜着看 根据左下到右上的方向进行分层,这样第i层只和第i-2层有关了

不过在将图斜过来的时候要细心呐

代码1:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<map>

#include<set>

#include<vector>

#include<stack>

#include<queue>

#include<algorithm>



#define LL long long

#define ULL unsigned long long

using namespace std;

const int INF=0x3f3f3f3f;

const int MOD=1000000007;

const int N=105;

const int M=205;

int a[N][N];

int b[N],len,b1[N],len1;

int can[1<<10][1<<10];

vector<int>vt[N];

int dp[N][M][M];

bool ok(int x,int y)

{

    len=0;

    while(y>0)

    {

        b[len++]=(y&1);

        y=y>>1;

    }

    for(int i=0;i<len;++i)

    if(b[i]==1&&((i-2>=0&&b[i-2]==1)||(a[x][i+1]==0)))

    return false;

    return true;

}

int fcan(int x,int y)

{

    len=0;

    while(x>0)

    {

        b[len++]=(x&1);

        x=x>>1;

    }

    len1=0;

    while(y>0)

    {

        b1[len1++]=(y&1);

        y=y>>1;

    }

    int sum=0;

    for(int i=0;i<len1;++i)

    if(b1[i]==1)

    {

        ++sum;

        if(i-1>=0&&i-1<len&&b[i-1]==1) return -1;

        if(i+1>=0&&i+1<len&&b[i+1]==1) return -1;

    }

    return sum;

}

int main()

{

    //freopen("data.in","r",stdin);

    for(int i=0;i<(1<<10);++i)

    for(int j=0;j<(1<<10);++j)

    can[i][j]=fcan(i,j);

    int n,m;

    while(cin>>n>>m)

    {

        for(int i=0;i<=n;++i)

        vt[i].clear();

        memset(a,0,sizeof(a));

        for(int i=1;i<=n;++i)

        for(int j=1;j<=m;++j)

        cin>>a[i][j];

        for(int i=1;i<=n;++i)

        for(int j=0;j<(1<<m);++j)

        if(ok(i,j))

        vt[i].push_back(j);

        vt[0].push_back(0);

        memset(dp,-1,sizeof(dp));

        for(unsigned int j=0;j<vt[1].size();++j)

        dp[1][0][j]=can[vt[0][0]][vt[1][j]];

        for(int i=2;i<=n;++i)

        for(unsigned int j=0;j<vt[i-1].size();++j)

        for(unsigned int l=0;l<vt[i].size();++l)

        if(can[vt[i-1][j]][vt[i][l]]!=-1)

        {//cout<<"T"<<endl;

            for(unsigned int r=0;r<vt[i-2].size();++r)

            if(can[vt[i-2][r]][vt[i-1][j]]!=-1&&dp[i-1][r][j]!=-1&&(vt[i][l]&vt[i-2][r])==0)

            {

                if(dp[i][j][l]==-1||dp[i][j][l]<dp[i-1][r][j]+can[vt[i-1][j]][vt[i][l]])

                dp[i][j][l]=dp[i-1][r][j]+can[vt[i-1][j]][vt[i][l]];

            }

        }

        int ans=0;

        for(unsigned int j=0;j<vt[n-1].size();++j)

        for(unsigned int l=0;l<vt[n].size();++l)

        if(dp[n][j][l]!=-1)

        ans=max(ans,dp[n][j][l]);

        printf("%d\n",ans);

    }



    return 0;

}

代码2:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<map>

#include<set>

#include<vector>

#include<stack>

#include<queue>



using namespace std;

const long long MOD=1000000007;

const int N=310;

const int M=(1<<10);

int dp[N][M];

int b[N][N];

int a[N][N];

int can[N][M];

bool CC[M][M];

int m,n;

int b1[N],len1,b2[N],len2;

void To()

{

    for(int i=1;i<=n;++i)

    {

        int r=1;

        int x=i,y=1;

        for(;x>0&&r<=m;--x,++y,r++)

        a[i][r]=b[x][y];

    }

    for(int j=2;j<=m;++j)

    {

        int r=j;

        int x=n,y=j;

        for(;x>0&&r<=m;--x,++y,++r)

        a[n+j-1][r]=b[x][y];

    }

}

int Fcan(int x,int y)

{

    len1=0;

    while(y>0)

    {

        b1[len1++]=(y&1);

        y=y>>1;

    }

    int sum=0;

    for(int i=0;i<len1;++i)

    if(b1[i]==1)

    {

        ++sum;

        if(i-1>=0&&b1[i-1]==1) return -1;

        if(a[x][i+1]==0) return -1;

    }

    return sum;

}

bool FCC(int x,int y)

{

    len1=0;

    while(x>0)

    {

        b1[len1++]=(x&1);

        x=x>>1;

    }

    len2=0;

    while(y>0)

    {

        b2[len2++]=(y&1);

        y=y>>1;

    }

    for(int i=0;i<len2;++i)

    if(b2[i]==1)

    {

        if(i-1>=0&&i-1<len1&&b1[i-1]==1)

        return false;

        if(i-2>=0&&i-2<len1&&b1[i-2]==1)

        return false;

        if(i>=0&&i<len1&&b1[i]==1)

        return false;

    }

    return true;

}

int main()

{

    //freopen("data.in","r",stdin);

    while(scanf("%d %d",&n,&m)!=EOF)

    {

        memset(dp,0,sizeof(dp));

        memset(a,0,sizeof(a));

        memset(b,0,sizeof(b));

        for(int i=1;i<=n;++i)

        for(int j=1;j<=m;++j)

        scanf("%d",&b[i][j]);

        To();

        int h=(1<<m);

        int E=n+m-1;

        for(int i=1;i<=E;++i)

        for(int j=0;j<h;++j)

        can[i][j]=Fcan(i,j);

        for(int i=0;i<h;++i)

        for(int j=0;j<h;++j)

        CC[i][j]=FCC(i,j);

        memset(dp,0,sizeof(dp));

        for(int i=1;i<=E;++i)

        for(int j=0;j<h;++j)

        {

            if(can[i][j]==-1) continue;

            if(i<=2)

            {dp[i][j]=can[i][j];continue;}

            for(int l=0;l<h;++l)

            if(can[i-2][l]!=-1)

            {

                if(CC[l][j])

                {

                    //if(i==8)

                    //cout<<i<<" "<<l<<" "<<j<<endl;

                    dp[i][j]=max(dp[i][j],dp[i-2][l]+can[i][j]);

                }

            }





        }

        int ans1=0,ans2=0;

        for(int j=0;j<h;++j)

        {

            ans1=max(ans1,dp[E-1][j]);

            ans2=max(ans2,dp[E][j]);

        }

        printf("%d\n",ans1+ans2);

    }

    return 0;

}

  

 

你可能感兴趣的:(HDU)