codeforces 111C Petya and Spiders 状态压缩

题目大意:有一个n*m的矩阵,最开始每个格子里有且仅有一个蜘蛛,每只蜘蛛可以向上下左右四个反向移动,也可以不动,问最后,最多有多少空地。


思路:

因为蜘蛛只能移动一步,那么想到用轮廓线状压。用二进制状态j表示当前轮廓线状态,1表示有蜘蛛,0表示没有蜘蛛。因为蜘蛛还可以向下和右边走,一排轮廓线是不够的,那么,再用一维表示下一个轮廓线的状态,1表示有蜘蛛到这里,0表示没有蜘蛛到这里。那么dp[ i ][ j ][ k ]表示,到第i个点,当前轮廓线状态为j,下一轮廓线状态为k,最多的空的数目。

后来,我突然想到我以前做过的一个题。发现那个问题其实和这个问题基本一致。那个问题是这样的,棋盘上可以放一些棋子,棋子的攻击范围是其本身和周围四个点,现在要使棋盘的每个点都被攻击,且棋子不能互相攻击,问,最少放几个棋子。如果把棋子不能互相攻击这个条件忽略,其实这两个题,想达到的目的就是一样的。棋子的最小值 == n*m-空地的最大值。这题可以用3进制压缩做,只需要一排轮廓线,0表示暂时没有被攻击,1表示已经被攻击了,2表示这个点放的是棋子。

我本来以为后者的方法要更好的,但是因为3进制数没有位运算,结果效率基本一致 o(╯□╰)o 但是,如果范围扩大的话,肯定是3进制压缩更好。


第一种:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef long long LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=100011122;
const double INFF=1e100;
const double eps=1e-8;
const LL mod=1000000007;
const int NN=100010;
const int MM=1000010;
/* ****************** */

int dp[2][1<<6][1<<6];
int go0[1<<6];

void solve(int n,int m)
{
    int t,i,j,k,mask=1<<m;
    int zt1,zt2,temp,ii,jj,ad,ans;
    for(i=0;i<2;i++)
        for(j=0;j<mask;j++)
            for(k=0;k<mask;k++)
                dp[i][j][k]=-INF;

    for(j=0;j<m;j++)
    {
        go0[j]=mask-1;
        go0[j]=go0[j]-(1<<j);
    }

    t=0;
    dp[t][mask-1][0]=0;

    for(ii=1;ii<=n;ii++)
        for(jj=0;jj<m;jj++)
        {
            t=1-t;
            for(j=0;j<mask;j++)
                for(k=0;k<mask;k++)
                    dp[t][j][k]=-INF;
            for(j=0;j<mask;j++)
                for(k=0;k<mask;k++)
                    if(dp[1-t][j][k]!=-INF)
                    {
                        temp=dp[1-t][j][k];

                        //bu dong
                        zt1=j|(1<<jj);
                        zt2=k&go0[jj];
                        dp[t][zt1][zt2]=max(dp[t][zt1][zt2],temp);

                        //shang
                        if(ii>1)
                        {
                            zt1=(j&go0[jj]) | ( (1<<jj)&k );
                            zt2=k&go0[jj];
                            if(zt1&(1<<jj))ad=0;
                            else ad=1;
                            if( ( j&(1<<jj) ) == 0 )ad--;
                            dp[t][zt1][zt2]=max(dp[t][zt1][zt2],temp+ad);
                        }

                        //xia
                        zt1=(j&go0[jj]) | ( (1<<jj)&k );
                        zt2=k|(1<<jj);
                        if(zt1&(1<<jj))ad=0;
                        else ad=1;
                        dp[t][zt1][zt2]=max(dp[t][zt1][zt2],temp+ad);

                        //zuo
                        if(jj>0)
                        {
                            zt1=(j&go0[jj]) | ( (1<<jj)&k );
                            zt1=zt1|( 1<<(jj-1) );
                            zt2=k&go0[jj];
                            if(zt1&(1<<jj))ad=0;
                            else ad=1;
                            if( ( j&( 1<<(jj-1) ) ) == 0 )ad--;
                            dp[t][zt1][zt2]=max(dp[t][zt1][zt2],temp+ad);
                        }

                        //you
                        if(jj+1<m)
                        {
                            zt1=(j&go0[jj]) | ( (1<<jj)&k );
                            zt2=k&go0[jj];
                            zt2=zt2|( 1<<(jj+1) );
                            if(zt1&(1<<jj))ad=0;
                            else ad=1;
                            dp[t][zt1][zt2]=max(dp[t][zt1][zt2],temp+ad);
                        }


                    }
        }

    ans=-INF;
    for(j=0;j<mask;j++)
        ans=max(ans,dp[t][j][0]);
    printf("%d\n",ans);
}

int main()
{
    int n,m;

    scanf("%d%d",&n,&m);
    if(m>n)
        swap(n,m);

    solve(n,m);


    return 0;
}

第二种,3进制压缩

/*
* this code is made by islands
* Problem: 1132
* Verdict: Accepted
* Submission Date: 2014-07-11 21:54:16
* Time: 48MS
* Memory: 9488KB
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef long long LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=100011122;
const double INFF=1e100;
const double eps=1e-8;
const LL mod=20120427;
const int NN=10;
const int MM=1000010;
/* ****************** */

int dp[2][800];
int pp3[15];
int a[15];
int temp[15];

void init(int t,int mask)
{
    int i;
    for(i=0;i<mask;i++)
        dp[t][i]=INF;
}

int main()
{
    int n,m;
    int i,j,k,mask,zt;
    int k1,t;
    int ans;
    bool fg;

    pp3[0]=1;
    for(i=1;i<=9;i++)
    {
        pp3[i]=pp3[i-1]*3;
    }

    scanf("%d%d",&n,&m);

    if(m>n)swap(n,m);

    mask=pp3[m];
    t=0;
    init(t,mask);
    zt=0;
    for(i=0;i<m;i++)
        zt+=pp3[i];
    dp[0][zt]=0;


  //  printf("mask==%d zt==%d\n",mask,zt);

    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            t=1-t;
            init(t,mask);
            for(k=0;k<mask;k++)
                if(dp[1-t][k]!=INF)
                {
                    zt=k;
                    a[0]=1;

                    for(k1=1;k1<=m;k1++)
                    {
                        a[k1]=zt%3;
                        zt/=3;
                    }

                    //fang attacker

                    for(k1=1;k1<=m;k1++)
                        temp[k1]=a[k1];
                    if(temp[j-1]==0)
                        temp[j-1]=1;
                    temp[j]=2;
                    zt=0;
                    for(k1=m;k1>=1;k1--)
                    {
                        zt=zt*3+temp[k1];
                    }
                  //  printf("check i==%d j==%d %d %d\n",i,j,dp[t][zt],dp[1-t][k]+1);
                    dp[t][zt]=min(dp[t][zt],dp[1-t][k]+1);

                    //bu fang
                    if(a[j]==0)
                        continue;

                    for(k1=1;k1<=m;k1++)
                        temp[k1]=a[k1];
                    if(a[j]==2 || a[j-1]==2)
                        temp[j]=1;
                    else
                        temp[j]=0;

                    zt=0;
                    for(k1=m;k1>=1;k1--)
                    {
                        zt=zt*3+temp[k1];
                    }
                 //   printf("check i==%d j==%d %d %d\n",i,j,dp[t][zt],dp[1-t][k]);
                    dp[t][zt]=min(dp[t][zt],dp[1-t][k]);
                }
        }

    ans=INF;
    for(k=0;k<mask;k++)
    {
        fg=false;
        zt=k;
        for(k1=1;k1<=m;k1++)
        {
            a[k1]=zt%3;
            zt/=3;
            if(a[k1]==0)
                fg=true;
        }
        if(!fg)
            ans=min(ans,dp[t][k]);
    }
    printf("%d\n",n*m-ans);
    
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值