HDU 4499 Cannon 解题报告

来源:互联网 发布:淘宝今天怎么了 编辑:程序博客网 时间:2024/05/18 02:19

通化邀请赛

题意:

一个最多5*5的棋盘,上面已有一些棋子(不是炮),现在要放置一些炮上去,使得按照中国象棋的规则不能互相吃掉对方。

解法:

题目没说清楚的地方是放上去的炮是不能移动的,但是题目里详细介绍了移动的规则。

可以用状压做,状态(i,j)表示(0,j)~(i,j)的状态,若有无炮兵则为0,一个炮兵和一个棋子(棋子在后,在前的话相当于2)为1,有一个炮兵为2,两个炮兵为3.

显然1和3不能再放炮,放了炮后0变为2,2变为3,遇到棋子3和2变为1,1变为0。

对于一行中可以用0 1 2 分别表示  不放   有棋子  放炮来表示。

数据很小,再暴力也能过。

#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <iostream>#include <vector>#define MAXN 1300#define INF 1000000007using namespace std;int dp[2][MAXN];int ma[10][10]={{0,1,2,3},{0,0,1,1},{2,-1,3,-1}};bool vi[10][10];int n,m,s,sum;int cal(int pre,int now){    int ans=0;    int num[5]={0},num2[5]={0};    for(int i=m-1;i>=0;--i,now/=3,pre/=4)        num[i]=now%3,num2[i]=pre%4;    for(int i=0;i<m;++i)    {        int a=num2[i],b=num[i];        if(ma[b][a]==-1)    return -1;        ans=ans*4+ma[b][a];    }    return ans;}void dfs(int h,int po,int ty,int pre,int now){    if(po==m)    {        int newt;        for(int i=0;i<MAXN;++i)        {            newt=cal(i,pre);            if(newt!=-1)                dp[!s][newt]=max(dp[!s][newt],now+dp[s][i]),sum=max(sum,now+dp[s][i]);        }    }    else    if(vi[h][po])   dfs(h,po+1,ma[1][ty],pre*3+1,now);    else    {        if(ty!=3&&ty!=1)    dfs(h,po+1,ma[2][ty],pre*3+2,now+1);        dfs(h,po+1,ty,pre*3,now);    }}int main(){    int q,ans=0;    while(scanf("%d%d%d",&n,&m,&q)==3)    {        for(int i=0;i<2;++i)            for(int j=0;j<MAXN;++j)                dp[i][j]=-INF;        dp[0][0]=0;        sum=0;        memset(vi,0,sizeof(vi));        for(int i=0;i<q;++i)        {            int a,b;            scanf("%d%d",&a,&b);            vi[a][b]=1;        }        s=0;        for(int i=0;i<n;++i)        {            for(int j=0;j<MAXN;++j)                dp[!s][j]=-INF;            dfs(i,0,0,0,0);            s=!s;        }        ans=sum;        for(int i=0;i<MAXN;++i)            ans=max(ans,dp[s][i]);        printf("%d\n",ans);    }    return 0;}