题意:
一个最多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 1000000007
using 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;
}