中文题,题意不再累赘。
思路:对于第 i 行的放士兵,影响它的只有第 i-1 行和 i-2 行,所以暴力枚举符合这三行的状态
state[i],state[j],state[k]. 接下来就是二进制的巧妙应用了。
具体题解看代码注释!!!
#include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath> #include<iostream> #include <queue> #include <stack> #include<algorithm> #include<set> using namespace std; #define INF 1e8 #define inf -0x3f3f3f3f #define eps 1e-8 #define LL long long #define N 100001 #define mol 100000000 int lp(int a,int b) { return a&b; } int dp[105][200][200];//dp[i][j][k],表示第 i 行是 state[j]状态i-1行是state[k]状态的最大值 int state[200];//符合规定的状态 int base[200];//给定矩阵的初始状态 int sum[200];//sum[i]:状态satet[i]的士兵数 int n,m,g; int main() { while(~scanf("%d%d",&n,&m)) { memset(base,0,sizeof(base)); memset(dp,0,sizeof(dp)); memset(state,0,sizeof(state)); memset(sum,0,sizeof(sum)); if(n==0||m==0) { printf("0\n"); continue; } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { scanf("%d",&g); if(g==0) base[i]+=1<<(j);//初始状态二进制表示 } } int num=0; for(int i=0;i<(1<<m);i++) { if(lp(i,i<<2)||lp(i,i>>2)) continue;//状态i要满足它不能攻击它的前两个和后两个 int k=i; while(k)//算出k有多少个1(士兵) { sum[num]+=k&1; k=k>>1; } state[num++]=i; } for(int i=0;i<num;i++)//初始第0行的状态 { if(lp(state[i],base[0])) continue; dp[0][i][0]=sum[i]; } for(int i=0;i<num;i++)//在满足第0行的状态下寻找第1行的状态 { if(lp(state[i],base[1])) continue; for(int j=0;j<num;j++) { if(lp(state[j],base[0])) continue; if(lp(state[j]<<1,state[i])||lp(state[j]>>1,state[i])) continue; dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+sum[i]); } } for(int i=0;i<num;i++)//在满足第0,1行的状态下寻找第2行的状态 { if(lp(state[i],base[2])) continue; for(int j=0;j<num;j++) { if(lp(state[j],base[1])) continue; for(int k=0;k<num;k++) { if(lp(state[k],base[0])) continue; if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue; if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue; if(lp(state[i],state[k])) continue; dp[2][i][j]=max(dp[2][i][j],dp[1][j][k]+sum[i]); } } } for(int r=3;r<n;r++)//从第3行开始 { for(int i=0;i<num;i++)//暴力枚举三行的状态state[i],state[j],state[k] { if(lp(base[r],state[i])) continue; for(int j=0;j<num;j++) { if(lp(base[r-1],state[j])) continue; if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue; for(int k=0;k<num;k++) { if(lp(base[r-2],state[k])) continue; if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue; if(lp(state[i],state[k])) continue; dp[r][i][j]=max(dp[r-1][j][k]+sum[i],dp[r][i][j]); } } } } int ans=0; for(int i=0;i<num;i++) { for(int j=0;j<num;j++) ans=max(ans,dp[n-1][i][j]); } printf("%d\n",ans); } return 0; } /* 6 6 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 1 0 0 1 0 1 1 0 1 3 3 1 1 1 1 1 1 1 1 1 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 6 1 6 1 1 1 1 1 1 2 6 1 1 1 1 1 1 1 1 1 1 1 1 Answer: 6 3 2 12 0 4 4 */