ZOJ 3755 - Mines (状压DP)

版权声明:是自己手打的没错 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);
	}



}

猜你喜欢

转载自blog.csdn.net/Mr_Treeeee/article/details/82874338