版权声明:是自己手打的没错 https://blog.csdn.net/Mr_Treeeee/article/details/82874338
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5178
题意:
大家都玩过扫雷吧。
给你n*m的扫雷数字。数字都在偶数列上。
也就是说,棋盘是n*(2*m+1)大小。
让你输出最少的雷数。
POINT:
n最大是10,暗示我们状压DP。
挺简单的,不阐述了。
#include <stdio.h>
#include <iostream>
const int inf = 0x3f3f3f3f;
int a[11][11];
int one[1027];
int dp[2][1027];
int n,m;
int check(int pre,int to,int j)
{
for(int i=1;i<=n;i++){
int num=0;
if(pre&(1<<i)) num++;
if(pre&(1<<(i-1))) num++;
if(pre&(1<<(i-2))) num++;
if(a[i][j]<num) return -1;
if(to&(1<<i)) num++;
if(to&(1<<(i-1))) num++;
if(to&(1<<(i-2))) num++;
if(a[i][j]!=num) return 0;
}
return 1;
}
int main()
{
for(int i=1;i<1024;i++){
one[i]=one[i-(i&-i)]+1;
}
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
}
int k=0;
for(int i=0;i<(1<<n);i++)
dp[k][i]=one[i],dp[!k][i]=inf;
for(int j=1;j<=m;j++){
for(int pre=0;pre<(1<<n);pre++)
for(int to=0;to<(1<<n);to++){
int op=check(pre,to,j);
if(op==-1) break;
else if(op){
dp[!k][to]=std::min(dp[!k][to],dp[k][pre]+one[to]);
}
}
for(int i=0;i<(1<<n);i++)
dp[k][i]=inf;
k=!k;
}
int ans=inf;
for(int i=0;i<(1<<n);i++){
ans=std::min(ans,dp[k][i]);
}
printf("%d\n",ans);
}
}